fix(basic.gblib): COPY and CONVERT is now generating good JS.
This commit is contained in:
parent
8614ff4a8e
commit
3f13609d59
13 changed files with 262 additions and 63 deletions
7
package-lock.json
generated
7
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "botserver",
|
"name": "botserver",
|
||||||
"version": "2.0.79",
|
"version": "2.0.91",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -20344,6 +20344,11 @@
|
||||||
"spdx-ranges": "^2.0.0"
|
"spdx-ranges": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"speakingurl": {
|
||||||
|
"version": "14.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
|
||||||
|
"integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="
|
||||||
|
},
|
||||||
"split": {
|
"split": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
|
||||||
|
|
|
@ -100,6 +100,7 @@
|
||||||
"sequelize": "5.21.5",
|
"sequelize": "5.21.5",
|
||||||
"sequelize-typescript": "1.1.0",
|
"sequelize-typescript": "1.1.0",
|
||||||
"simple-git": "2.23.0",
|
"simple-git": "2.23.0",
|
||||||
|
"speakingurl": "^14.0.1",
|
||||||
"sppull": "2.6.7",
|
"sppull": "2.6.7",
|
||||||
"strict-password-generator": "1.1.2",
|
"strict-password-generator": "1.1.2",
|
||||||
"swagger-client": "2.1.18",
|
"swagger-client": "2.1.18",
|
||||||
|
|
|
@ -49,6 +49,7 @@ import { GuaribasAdmin } from '../models/AdminModel';
|
||||||
const Path = require('path');
|
const Path = require('path');
|
||||||
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;
|
||||||
|
const crypto = require("crypto");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Services for server administration.
|
* Services for server administration.
|
||||||
|
@ -145,6 +146,21 @@ export class GBAdminService implements IGBAdminService {
|
||||||
return passwordGenerator.generatePassword(options);
|
return passwordGenerator.generatePassword(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://stackoverflow.com/a/52171480
|
||||||
|
*/
|
||||||
|
public static getHash(str, seed = 0) {
|
||||||
|
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
||||||
|
for (let i = 0, ch; i < str.length; i++) {
|
||||||
|
ch = str.charCodeAt(i);
|
||||||
|
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||||
|
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||||
|
}
|
||||||
|
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||||
|
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||||
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
||||||
|
}
|
||||||
|
|
||||||
public static async undeployPackageCommand(text: any, min: GBMinInstance) {
|
public static async undeployPackageCommand(text: any, min: GBMinInstance) {
|
||||||
const packageName = text.split(' ')[1];
|
const packageName = text.split(' ')[1];
|
||||||
const importer = new GBImporter(min.core);
|
const importer = new GBImporter(min.core);
|
||||||
|
@ -176,7 +192,7 @@ export class GBAdminService implements IGBAdminService {
|
||||||
// .gbot packages are handled using storage API, so no download
|
// .gbot packages are handled using storage API, so no download
|
||||||
// of local resources is required.
|
// of local resources is required.
|
||||||
|
|
||||||
|
|
||||||
if (!localFolder.endsWith('.gbot')) {
|
if (!localFolder.endsWith('.gbot')) {
|
||||||
GBLog.warn(`${GBConfigService.get('CLOUD_USERNAME')} must be authorized on SharePoint related site to download to: ${localFolder}`);
|
GBLog.warn(`${GBConfigService.get('CLOUD_USERNAME')} must be authorized on SharePoint related site to download to: ${localFolder}`);
|
||||||
await s.downloadFolder(
|
await s.downloadFolder(
|
||||||
|
@ -261,7 +277,7 @@ export class GBAdminService implements IGBAdminService {
|
||||||
const refreshToken = await this.getValue(instanceId, 'refreshToken');
|
const refreshToken = await this.getValue(instanceId, 'refreshToken');
|
||||||
const resource = 'https://graph.microsoft.com';
|
const resource = 'https://graph.microsoft.com';
|
||||||
const authenticationContext = new AuthenticationContext(authorizationUrl);
|
const authenticationContext = new AuthenticationContext(authorizationUrl);
|
||||||
|
|
||||||
authenticationContext.acquireTokenWithRefreshToken(
|
authenticationContext.acquireTokenWithRefreshToken(
|
||||||
refreshToken,
|
refreshToken,
|
||||||
instance.marketplaceId,
|
instance.marketplaceId,
|
||||||
|
|
|
@ -289,8 +289,12 @@ export class GBVMService extends GBService {
|
||||||
return `sendFile (step, ${$3})\n`;
|
return `sendFile (step, ${$3})\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
code = code.replace(/(COPY)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/(copy)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
return `sys().copyFile (step, ${$3})\n`;
|
return `sys().copyFile(step, ${$3})\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
code = code.replace(/(convert)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
|
return `sys().convert(step, ${$3})\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
code = code.replace(/(save)(\s)(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/(save)(\s)(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
|
@ -433,9 +437,6 @@ export class GBVMService extends GBService {
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsendFileTo\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsendFileTo\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.sendFileTo' : $1;
|
return $1 === undefined ? 'this.sendFileTo' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bcopyFile\b/gi, ($0, $1) => {
|
|
||||||
return $1 === undefined ? 'this.copyFile' : $1;
|
|
||||||
});
|
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsendFile\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsendFile\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.sendFile' : $1;
|
return $1 === undefined ? 'this.sendFile' : $1;
|
||||||
});
|
});
|
||||||
|
@ -448,7 +449,7 @@ export class GBVMService extends GBService {
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bmenu\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bmenu\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.menu' : $1;
|
return $1 === undefined ? 'this.menu' : $1;
|
||||||
});
|
});
|
||||||
|
|
||||||
// await insertion.
|
// await insertion.
|
||||||
|
|
||||||
code = code.replace(/this\./gm, 'await this.');
|
code = code.replace(/this\./gm, 'await this.');
|
||||||
|
|
|
@ -186,7 +186,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
const instances = await core.loadInstances();
|
const instances = await core.loadInstances();
|
||||||
await CollectionUtil.asyncForEach(instances, async instance => {
|
await CollectionUtil.asyncForEach(instances, async instance => {
|
||||||
this.mountGBKBAssets(`${instance.botId}.gbkb`,
|
this.mountGBKBAssets(`${instance.botId}.gbkb`,
|
||||||
instance.botId, `${instance.botId}.gbkb`);
|
instance.botId, `${instance.botId}.gbkb`);
|
||||||
});
|
});
|
||||||
|
|
||||||
GBLog.info(`Package deployment done.`);
|
GBLog.info(`Package deployment done.`);
|
||||||
|
@ -320,7 +320,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
public async publishNLP(instance: IGBInstance): Promise<void> {
|
public async publishNLP(instance: IGBInstance): Promise<void> {
|
||||||
const service = new AzureDeployerService(this);
|
const service = new AzureDeployerService(this);
|
||||||
const res = await service.publishNLP(instance.cloudLocation, instance.nlpAppId,
|
const res = await service.publishNLP(instance.cloudLocation, instance.nlpAppId,
|
||||||
instance.nlpAuthoringKey);
|
instance.nlpAuthoringKey);
|
||||||
if (res.status !== 200 && res.status !== 201) { throw res.bodyAsText; }
|
if (res.status !== 200 && res.status !== 201) { throw res.bodyAsText; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,29 +371,29 @@ export class GBDeployer implements IGBDeployer {
|
||||||
const libraryId = process.env.STORAGE_LIBRARY;
|
const libraryId = process.env.STORAGE_LIBRARY;
|
||||||
|
|
||||||
GBLog.info(`Connecting to Config.xslx (siteId: ${siteId}, libraryId: ${libraryId})...`);
|
GBLog.info(`Connecting to Config.xslx (siteId: ${siteId}, libraryId: ${libraryId})...`);
|
||||||
|
|
||||||
// Connects to MSFT storage.
|
// Connects to MSFT storage.
|
||||||
|
|
||||||
const token = await min.adminService.acquireElevatedToken(min.instance.instanceId);
|
const token = await min.adminService.acquireElevatedToken(min.instance.instanceId);
|
||||||
const client = MicrosoftGraph.Client.init({
|
const client = MicrosoftGraph.Client.init({
|
||||||
authProvider: done => {
|
authProvider: done => {
|
||||||
done(null, token);
|
done(null, token);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Retrieves all files in .bot folder.
|
// Retrieves all files in .bot folder.
|
||||||
|
|
||||||
const botId = min.instance.botId;
|
const botId = min.instance.botId;
|
||||||
const path = `/${botId}.gbai/${botId}.gbot`;
|
const path = `/${botId}.gbai/${botId}.gbot`;
|
||||||
let url = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:${path}:/children`;
|
let url = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:${path}:/children`;
|
||||||
|
|
||||||
GBLog.info(`Loading .gbot from Excel: ${url}`);
|
GBLog.info(`Loading .gbot from Excel: ${url}`);
|
||||||
const res = await client
|
const res = await client
|
||||||
.api(url)
|
.api(url)
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
// Finds Config.xlsx.
|
// Finds Config.xlsx.
|
||||||
|
|
||||||
const document = res.value.filter(m => {
|
const document = res.value.filter(m => {
|
||||||
return m.name === 'Config.xlsx';
|
return m.name === 'Config.xlsx';
|
||||||
});
|
});
|
||||||
|
@ -496,14 +496,14 @@ export class GBDeployer implements IGBDeployer {
|
||||||
if (handled) {
|
if (handled) {
|
||||||
return pck;
|
return pck;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deploy platform packages here accordingly to their extension.
|
// Deploy platform packages here accordingly to their extension.
|
||||||
|
|
||||||
switch (packageType) {
|
switch (packageType) {
|
||||||
case '.gbot':
|
case '.gbot':
|
||||||
|
|
||||||
// Extracts configuration information from .gbot files.
|
// Extracts configuration information from .gbot files.
|
||||||
|
|
||||||
if (process.env.ENABLE_PARAMS_ONLINE === 'false') {
|
if (process.env.ENABLE_PARAMS_ONLINE === 'false') {
|
||||||
if (Fs.existsSync(localPath)) {
|
if (Fs.existsSync(localPath)) {
|
||||||
GBLog.info(`Loading .gbot from ${localPath}.`);
|
GBLog.info(`Loading .gbot from ${localPath}.`);
|
||||||
|
@ -512,9 +512,9 @@ export class GBDeployer implements IGBDeployer {
|
||||||
} else {
|
} else {
|
||||||
min.instance.params = await this.loadParamsFromTabular(min);
|
min.instance.params = await this.loadParamsFromTabular(min);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates instance object.
|
// Updates instance object.
|
||||||
|
|
||||||
await this.core.saveInstance(min.instance);
|
await this.core.saveInstance(min.instance);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -561,6 +561,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
const err = GBError.create(`Unhandled package type: ${packageType}.`);
|
const err = GBError.create(`Unhandled package type: ${packageType}.`);
|
||||||
Promise.reject(err);
|
Promise.reject(err);
|
||||||
break;
|
break;
|
||||||
|
@ -581,6 +582,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
// Removes objects from storage, cloud resources and local files if any.
|
// Removes objects from storage, cloud resources and local files if any.
|
||||||
|
|
||||||
switch (packageType) {
|
switch (packageType) {
|
||||||
|
|
||||||
case '.gbot':
|
case '.gbot':
|
||||||
const packageObject = JSON.parse(Fs.readFileSync(urlJoin(localPath, 'package.json'), 'utf8'));
|
const packageObject = JSON.parse(Fs.readFileSync(urlJoin(localPath, 'package.json'), 'utf8'));
|
||||||
await this.undeployBot(packageObject.botId, packageName);
|
await this.undeployBot(packageObject.botId, packageName);
|
||||||
|
@ -596,17 +598,17 @@ export class GBDeployer implements IGBDeployer {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '.gbtheme':
|
case '.gbtheme':
|
||||||
rimraf.sync(localPath);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '.gbdialog':
|
case '.gbdialog':
|
||||||
rimraf.sync(localPath);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '.gblib':
|
case '.gblib':
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '.gbapp':
|
case '.gbapp':
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
const err = GBError.create(`Unhandled package type: ${packageType}.`);
|
const err = GBError.create(`Unhandled package type: ${packageType}.`);
|
||||||
Promise.reject(err);
|
Promise.reject(err);
|
||||||
|
@ -647,6 +649,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the index.
|
// Removes the index.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await search.deleteIndex();
|
await search.deleteIndex();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -659,6 +662,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates the data source and index on the cloud.
|
// Creates the data source and index on the cloud.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await search.createDataSource(dsName, dsName, 'GuaribasQuestion', 'azuresql', connectionString);
|
await search.createDataSource(dsName, dsName, 'GuaribasQuestion', 'azuresql', connectionString);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -694,7 +698,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
|
|
||||||
if (!Fs.existsSync(`${root}/build`) && process.env.DISABLE_WEB !== 'true') {
|
if (!Fs.existsSync(`${root}/build`) && process.env.DISABLE_WEB !== 'true') {
|
||||||
|
|
||||||
// Write a .env required to fix some bungs in create-react-app facility.
|
// Write a .env required to fix some bungs in create-react-app tool.
|
||||||
|
|
||||||
Fs.writeFileSync(`${root}/.env`, 'SKIP_PREFLIGHT_CHECK=true');
|
Fs.writeFileSync(`${root}/.env`, 'SKIP_PREFLIGHT_CHECK=true');
|
||||||
|
|
||||||
|
@ -702,15 +706,18 @@ export class GBDeployer implements IGBDeployer {
|
||||||
|
|
||||||
GBLog.info(`Installing modules default.gbui (It may take a few minutes)...`);
|
GBLog.info(`Installing modules default.gbui (It may take a few minutes)...`);
|
||||||
child_process.execSync(`${npm} install`, { cwd: root });
|
child_process.execSync(`${npm} install`, { cwd: root });
|
||||||
|
|
||||||
GBLog.info(`Transpiling default.gbui...`);
|
GBLog.info(`Transpiling default.gbui...`);
|
||||||
child_process.execSync(`${npm} run build`, { cwd: root });
|
child_process.execSync(`${npm} run build`, { cwd: root });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up node_modules folder as it is only needed during compile time.
|
// Clean up node_modules folder as it is only needed during compile time.
|
||||||
|
|
||||||
GBLog.info(`Cleaning default.gbui node_modules...`);
|
|
||||||
const nodeModules = urlJoin(root, 'node_modules');
|
const nodeModules = urlJoin(root, 'node_modules');
|
||||||
rimraf.sync(nodeModules);
|
if (Fs.existsSync(nodeModules)) {
|
||||||
|
rimraf.sync(nodeModules);
|
||||||
|
GBLog.info(`Cleaning default.gbui node_modules...`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -729,13 +736,13 @@ export class GBDeployer implements IGBDeployer {
|
||||||
|
|
||||||
const gbaiName = `${botId}.gbai`;
|
const gbaiName = `${botId}.gbai`;
|
||||||
GBServer.globals.server.use(`/kb/${gbaiName}/${packageName}/assets`,
|
GBServer.globals.server.use(`/kb/${gbaiName}/${packageName}/assets`,
|
||||||
express.static(urlJoin('work', gbaiName, filename, 'assets')));
|
express.static(urlJoin('work', gbaiName, filename, 'assets')));
|
||||||
GBServer.globals.server.use(`/kb/${gbaiName}/${packageName}/images`,
|
GBServer.globals.server.use(`/kb/${gbaiName}/${packageName}/images`,
|
||||||
express.static(urlJoin('work', gbaiName, filename, 'images')));
|
express.static(urlJoin('work', gbaiName, filename, 'images')));
|
||||||
GBServer.globals.server.use(`/kb/${gbaiName}/${packageName}/audios`,
|
GBServer.globals.server.use(`/kb/${gbaiName}/${packageName}/audios`,
|
||||||
express.static(urlJoin('work', gbaiName, filename, 'audios')));
|
express.static(urlJoin('work', gbaiName, filename, 'audios')));
|
||||||
GBServer.globals.server.use(`/kb/${gbaiName}/${packageName}/videos`,
|
GBServer.globals.server.use(`/kb/${gbaiName}/${packageName}/videos`,
|
||||||
express.static(urlJoin('work', gbaiName, filename, 'videos')));
|
express.static(urlJoin('work', gbaiName, filename, 'videos')));
|
||||||
|
|
||||||
GBLog.info(`KB (.gbkb) assets accessible at: /kb/${botId}.gbai/${packageName}.`);
|
GBLog.info(`KB (.gbkb) assets accessible at: /kb/${botId}.gbai/${packageName}.`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,7 @@ export class GBMinService {
|
||||||
public async buildMin(instances: IGBInstance[]) {
|
public async buildMin(instances: IGBInstance[]) {
|
||||||
|
|
||||||
// Servers default UI on root address '/' if web enabled.
|
// Servers default UI on root address '/' if web enabled.
|
||||||
|
|
||||||
if (process.env.DISABLE_WEB !== 'true') {
|
if (process.env.DISABLE_WEB !== 'true') {
|
||||||
const url = GBServer.globals.wwwroot
|
const url = GBServer.globals.wwwroot
|
||||||
? GBServer.globals.wwwroot
|
? GBServer.globals.wwwroot
|
||||||
|
@ -139,6 +140,8 @@ export class GBMinService {
|
||||||
GBServer.globals.server.use('/', express.static(url));
|
GBServer.globals.server.use('/', express.static(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Servers the bot information object via HTTP so clients can get
|
// Servers the bot information object via HTTP so clients can get
|
||||||
// instance information stored on server.
|
// instance information stored on server.
|
||||||
|
|
||||||
|
@ -216,12 +219,13 @@ export class GBMinService {
|
||||||
|
|
||||||
await this.invokeLoadBot(GBServer.globals.appPackages, GBServer.globals.sysPackages, min);
|
await this.invokeLoadBot(GBServer.globals.appPackages, GBServer.globals.sysPackages, min);
|
||||||
|
|
||||||
// Serves individual URL for each bot conversational interface...
|
// Serves individual URL for each bot conversational interface.
|
||||||
|
|
||||||
const url = `/api/messages/${instance.botId}`;
|
const receiver = async (req, res) => {
|
||||||
GBServer.globals.server.post(url, async (req, res) => {
|
|
||||||
await this.receiver(adapter, req, res, conversationState, min, instance, GBServer.globals.appPackages);
|
await this.receiver(adapter, req, res, conversationState, min, instance, GBServer.globals.appPackages);
|
||||||
});
|
};
|
||||||
|
const url = `/api/messages/${instance.botId}`;
|
||||||
|
GBServer.globals.server.post(url, receiver);
|
||||||
GBLog.info(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
|
GBLog.info(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
|
||||||
|
|
||||||
// Serves individual URL for each bot user interface.
|
// Serves individual URL for each bot user interface.
|
||||||
|
@ -237,7 +241,14 @@ export class GBMinService {
|
||||||
uiUrlAlt,
|
uiUrlAlt,
|
||||||
express.static(urlJoin(GBDeployer.deployFolder, GBMinService.uiPackage, 'build'))
|
express.static(urlJoin(GBDeployer.deployFolder, GBMinService.uiPackage, 'build'))
|
||||||
);
|
);
|
||||||
|
const domain = min.core.getParam(min.instance, 'Domain', null);
|
||||||
|
if (domain) {
|
||||||
|
GBServer.globals.server.use(
|
||||||
|
domain,
|
||||||
|
express.static(urlJoin(GBDeployer.deployFolder, GBMinService.uiPackage, 'build'))
|
||||||
|
);
|
||||||
|
GBLog.info(`Bot UI ${GBMinService.uiPackage} accessible at custom domain: ${domain}.`);
|
||||||
|
}
|
||||||
GBLog.info(`Bot UI ${GBMinService.uiPackage} accessible at: ${uiUrl} and ${uiUrlAlt}.`);
|
GBLog.info(`Bot UI ${GBMinService.uiPackage} accessible at: ${uiUrl} and ${uiUrlAlt}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +523,12 @@ export class GBMinService {
|
||||||
speechToken: speechToken,
|
speechToken: speechToken,
|
||||||
conversationId: webchatTokenContainer.conversationId,
|
conversationId: webchatTokenContainer.conversationId,
|
||||||
authenticatorTenant: instance.authenticatorTenant,
|
authenticatorTenant: instance.authenticatorTenant,
|
||||||
authenticatorClientId: instance.marketplaceId
|
authenticatorClientId: instance.marketplaceId,
|
||||||
|
paramLogoImageUrl: this.core.getParam(instance, 'Logo Image Url', null),
|
||||||
|
paramLogoImageAlt: this.core.getParam(instance, 'Logo Image Alt', null),
|
||||||
|
paramLogoImageWidth: this.core.getParam(instance, 'Logo Image Width', null),
|
||||||
|
paramLogoImageHeight: this.core.getParam(instance, 'Logo Image Height', null),
|
||||||
|
paramLogoImageType: this.core.getParam(instance, 'Logo Image Type', null)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -603,6 +619,7 @@ export class GBMinService {
|
||||||
if (GBServer.globals.minBoot === undefined) {
|
if (GBServer.globals.minBoot === undefined) {
|
||||||
GBServer.globals.minBoot = min;
|
GBServer.globals.minBoot = min;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: min.appPackages = core.getPackagesByInstanceId(min.instance.instanceId);
|
// TODO: min.appPackages = core.getPackagesByInstanceId(min.instance.instanceId);
|
||||||
|
|
||||||
// Creates a hub of services available in .gbapps.
|
// Creates a hub of services available in .gbapps.
|
||||||
|
@ -735,7 +752,7 @@ export class GBMinService {
|
||||||
user.welcomed = false;
|
user.welcomed = false;
|
||||||
firstTime = true;
|
firstTime = true;
|
||||||
|
|
||||||
// Sends loadInstance event to .gbui clients.
|
// Sends loadInstance event to .gbui clients and loads FAQ.
|
||||||
|
|
||||||
await min.conversationalService.sendEvent(min, step, 'loadInstance', {
|
await min.conversationalService.sendEvent(min, step, 'loadInstance', {
|
||||||
instanceId: instance.instanceId,
|
instanceId: instance.instanceId,
|
||||||
|
@ -743,6 +760,12 @@ export class GBMinService {
|
||||||
theme: instance.theme ? instance.theme : 'default.gbtheme',
|
theme: instance.theme ? instance.theme : 'default.gbtheme',
|
||||||
secret: instance.webchatKey
|
secret: instance.webchatKey
|
||||||
});
|
});
|
||||||
|
const service = new KBService(min.core.sequelize);
|
||||||
|
const data = await service.getFaqBySubjectArray('faq', undefined);
|
||||||
|
await min.conversationalService.sendEvent(min, step, 'play', {
|
||||||
|
playerType: 'bullet',
|
||||||
|
data: data.slice(0, 10)
|
||||||
|
});
|
||||||
|
|
||||||
// This same event is dispatched either to all participants
|
// This same event is dispatched either to all participants
|
||||||
// including the bot, that is filtered bellow.
|
// including the bot, that is filtered bellow.
|
||||||
|
|
36
packages/default.gbui/package-lock.json
generated
36
packages/default.gbui/package-lock.json
generated
|
@ -1199,6 +1199,11 @@
|
||||||
"@types/yargs": "^13.0.0"
|
"@types/yargs": "^13.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@midudev/react-static-content": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@midudev/react-static-content/-/react-static-content-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-P2+rdqhysYNon5/noOoUiFJghVxbl64qGgxsKwe10mjrkQvgIy4vCcOLN5Nw00er/cBSuWY/hVHkuSeQ6sI5VA=="
|
||||||
|
},
|
||||||
"@mrmlnc/readdir-enhanced": {
|
"@mrmlnc/readdir-enhanced": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||||
|
@ -11919,6 +11924,37 @@
|
||||||
"shallowequal": "^1.0.1"
|
"shallowequal": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-super-seo": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-super-seo/-/react-super-seo-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-OtenkmcfjA97kaem/HxL0oaRO3hYhfalaoNt2I1nAVMzGh3I/xDWwy+J4ynA6LlPc+SqBY5BHcrRzjWT75hr1A==",
|
||||||
|
"requires": {
|
||||||
|
"react-helmet": "^6.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react-fast-compare": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
|
||||||
|
},
|
||||||
|
"react-helmet": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==",
|
||||||
|
"requires": {
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react-fast-compare": "^3.1.1",
|
||||||
|
"react-side-effect": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-side-effect": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-transition-group": {
|
"react-transition-group": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.3.0.tgz",
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"homepage": ".",
|
"homepage": ".",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@midudev/react-static-content": "^1.0.4",
|
||||||
"ajv": "^6.10.2",
|
"ajv": "^6.10.2",
|
||||||
"botframework-directlinejs": "0.11.6",
|
"botframework-directlinejs": "0.11.6",
|
||||||
"botframework-webchat": "^4.7.1",
|
"botframework-webchat": "^4.7.1",
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
"react-player": "^1.14.2",
|
"react-player": "^1.14.2",
|
||||||
"react-powerbi": "0.5.2",
|
"react-powerbi": "0.5.2",
|
||||||
"react-scripts": "^3.3.0",
|
"react-scripts": "^3.3.0",
|
||||||
|
"react-super-seo": "^1.0.5",
|
||||||
"react-transition-group": "^4.3.0",
|
"react-transition-group": "^4.3.0",
|
||||||
"rxjs": "^6.5.4",
|
"rxjs": "^6.5.4",
|
||||||
"url-join": "4.0.1"
|
"url-join": "4.0.1"
|
||||||
|
|
|
@ -37,12 +37,13 @@ import GBVideoPlayer from './players/GBVideoPlayer.js';
|
||||||
import GBLoginPlayer from './players/GBLoginPlayer.js';
|
import GBLoginPlayer from './players/GBLoginPlayer.js';
|
||||||
import GBBulletPlayer from './players/GBBulletPlayer.js';
|
import GBBulletPlayer from './players/GBBulletPlayer.js';
|
||||||
import SidebarMenu from './components/SidebarMenu.js';
|
import SidebarMenu from './components/SidebarMenu.js';
|
||||||
|
import SEO from './components/SEO.js';
|
||||||
import GBCss from './components/GBCss.js';
|
import GBCss from './components/GBCss.js';
|
||||||
import { DirectLine } from 'botframework-directlinejs';
|
import { DirectLine } from 'botframework-directlinejs';
|
||||||
import { ConnectionStatus } from 'botframework-directlinejs';
|
import { ConnectionStatus } from 'botframework-directlinejs';
|
||||||
import ReactWebChat from 'botframework-webchat';
|
import ReactWebChat from 'botframework-webchat';
|
||||||
import { UserAgentApplication } from 'msal';
|
import { UserAgentApplication } from 'msal';
|
||||||
|
import StaticContent from '@midudev/react-static-content'
|
||||||
|
|
||||||
class GBUIApp extends React.Component {
|
class GBUIApp extends React.Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -138,7 +139,7 @@ class GBUIApp extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticate() {
|
authenticate() {
|
||||||
|
|
||||||
if (this.state.instanceClient.authenticatorClientId === null) {
|
if (this.state.instanceClient.authenticatorClientId === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -343,14 +344,17 @@ class GBUIApp extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<StaticContent>
|
||||||
{gbCss}
|
<SEO></SEO>
|
||||||
{sideBar}
|
<div>
|
||||||
<div className="player">{playerComponent}</div>
|
{gbCss}
|
||||||
<div className="webchat">
|
{sideBar}
|
||||||
{chat}
|
<div className="player">{playerComponent}</div>
|
||||||
|
<div className="webchat">
|
||||||
|
{chat}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</StaticContent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
58
packages/default.gbui/src/components/SEO.js
Normal file
58
packages/default.gbui/src/components/SEO.js
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| ( )_ _ |
|
||||||
|
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||||
|
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
||||||
|
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
|
||||||
|
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||||
|
| | | ( )_) | |
|
||||||
|
| (_) \___/' |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of Pragmatismo.io. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
|
import { SuperSEO } from 'react-super-seo';
|
||||||
|
|
||||||
|
const footer = () => (
|
||||||
|
<SuperSEO
|
||||||
|
title={this.props.instance.title}
|
||||||
|
description={this.props.instance.description}
|
||||||
|
lang="en"
|
||||||
|
openGraph={{
|
||||||
|
ogImage: {
|
||||||
|
ogImage: this.props.instance.paramLogoImageUrl,
|
||||||
|
ogImageAlt: this.props.instance.paramLogoImageAlt,
|
||||||
|
ogImageWidth: this.props.instance.paramLogoImageWidth,
|
||||||
|
ogImageHeight: this.props.instance.paramLogoImageHeight,
|
||||||
|
ogImageType: this.props.instance.paramLogoImageType,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
twitter={{
|
||||||
|
twitterSummaryCard: {
|
||||||
|
summaryCardImage: this.props.instance.paramLogoImageUrl,
|
||||||
|
summaryCardImageAlt: this.props.instance.paramLogoImageAlt,
|
||||||
|
summaryCardSiteUsername: this.props.instance.paramTwitterUsername,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>);
|
||||||
|
export default footer
|
|
@ -50,11 +50,10 @@ class SideBarMenu extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="tittleSideBarMenu">
|
<div className="tittleSideBarMenu">
|
||||||
<img
|
<img
|
||||||
className="pragmatismoLogo"
|
className="pragmatismoLogo"
|
||||||
src={"/themes/" + this.props.instance.theme + "/images/logo.png"}
|
src={"/themes/" + this.props.instance.theme + "/images/logo.png"}
|
||||||
alt="General Bots Logo"
|
alt="General Bots Logo" />
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="SidebarMenu">
|
<div className="SidebarMenu">
|
||||||
|
@ -72,16 +71,14 @@ class SideBarMenu extends React.Component {
|
||||||
<div className="iconMenu">
|
<div className="iconMenu">
|
||||||
<span
|
<span
|
||||||
className="iconText"
|
className="iconText"
|
||||||
onClick={() => this.send("showSubjects")}
|
onClick={() => this.send("showSubjects")}>
|
||||||
>
|
|
||||||
Subjects
|
Subjects
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="iconMenu">
|
<div className="iconMenu">
|
||||||
<span
|
<span
|
||||||
className="iconText"
|
className="iconText"
|
||||||
onClick={() => this.send("giveFeedback")}
|
onClick={() => this.send("giveFeedback")}>
|
||||||
>
|
|
||||||
Suggestions
|
Suggestions
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -44,6 +44,7 @@ const walkPromise = require('walk-promise');
|
||||||
// tslint:disable-next-line:newline-per-chained-call
|
// tslint:disable-next-line:newline-per-chained-call
|
||||||
const { SearchService } = require('azure-search-client');
|
const { SearchService } = require('azure-search-client');
|
||||||
const Excel = require('exceljs');
|
const Excel = require('exceljs');
|
||||||
|
const getSlug = require('speakingurl');
|
||||||
import {
|
import {
|
||||||
GBDialogStep,
|
GBDialogStep,
|
||||||
GBLog,
|
GBLog,
|
||||||
|
@ -53,15 +54,14 @@ import {
|
||||||
IGBInstance,
|
IGBInstance,
|
||||||
IGBKBService
|
IGBKBService
|
||||||
} from 'botlib';
|
} from 'botlib';
|
||||||
|
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
|
||||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
import { Op } from 'sequelize';
|
import { Op } from 'sequelize';
|
||||||
import { Sequelize } from 'sequelize-typescript';
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
import { GBServer } from '../../../src/app';
|
|
||||||
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
|
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
|
||||||
import { GuaribasPackage } from '../../core.gbapp/models/GBModel';
|
import { GuaribasPackage } from '../../core.gbapp/models/GBModel';
|
||||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
|
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
|
||||||
import { CSService } from '../../customer-satisfaction.gbapp/services/CSService';
|
import { CSService } from '../../customer-satisfaction.gbapp/services/CSService';
|
||||||
import { SecService } from '../../security.gbapp/services/SecService';
|
|
||||||
import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from '../models';
|
import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from '../models';
|
||||||
import { Messages } from '../strings';
|
import { Messages } from '../strings';
|
||||||
import { GBConfigService } from './../../core.gbapp/services/GBConfigService';
|
import { GBConfigService } from './../../core.gbapp/services/GBConfigService';
|
||||||
|
@ -137,6 +137,54 @@ export class KBService implements IGBKBService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a question object given a SEO friendly URL.
|
||||||
|
*/
|
||||||
|
public async getQuestionIdFromURL(core: IGBCoreService, url: string) {
|
||||||
|
|
||||||
|
// Extracts questionId from URL.
|
||||||
|
|
||||||
|
const id = url.substr(url.lastIndexOf('-') + 1);
|
||||||
|
|
||||||
|
// Extracts botId from URL.
|
||||||
|
|
||||||
|
let path = /(http[s]?:\/\/)?([^\/\s]+\/)(.*)/gi;
|
||||||
|
const botId = url.replace(path, ($0, $1, $2, $3) => {
|
||||||
|
return $3.substr($3.indexOf('/'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Finds the associated question.
|
||||||
|
|
||||||
|
const instance = await core.loadInstanceByBotId(botId);
|
||||||
|
const question = await GuaribasQuestion.findAll({
|
||||||
|
where: {
|
||||||
|
instanceId: instance.instanceId,
|
||||||
|
questionId: id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return question;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getQuestionsSEO(instanceId: number) {
|
||||||
|
|
||||||
|
const questions = await GuaribasQuestion.findAll({
|
||||||
|
where: {
|
||||||
|
instanceId: instanceId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = [];
|
||||||
|
for (let i = 0; i < questions.length; i++) {
|
||||||
|
const answer = questions[i];
|
||||||
|
const text = getSlug(answer.content);
|
||||||
|
let url = `${text}-${i}`;
|
||||||
|
output.push(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
public async getAnswerByText(instanceId: number, text: string): Promise<any> {
|
public async getAnswerByText(instanceId: number, text: string): Promise<any> {
|
||||||
text = text.trim();
|
text = text.trim();
|
||||||
const service = new CSService();
|
const service = new CSService();
|
||||||
|
@ -519,6 +567,7 @@ export class KBService implements IGBKBService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async importKbTabularDirectory(localPath: string, instance: IGBInstance, packageId: number): Promise<any> {
|
public async importKbTabularDirectory(localPath: string, instance: IGBInstance, packageId: number): Promise<any> {
|
||||||
const files = await walkPromise(localPath);
|
const files = await walkPromise(localPath);
|
||||||
|
|
||||||
|
|
|
@ -62,8 +62,8 @@ export class RootData {
|
||||||
public appPackages: any[]; // Loaded .gbapp package list
|
public appPackages: any[]; // Loaded .gbapp package list
|
||||||
public minService: GBMinService; // Minimalist service core
|
public minService: GBMinService; // Minimalist service core
|
||||||
public bootInstance: IGBInstance; // General Bot Interface Instance
|
public bootInstance: IGBInstance; // General Bot Interface Instance
|
||||||
public minInstances: any[]; //
|
public minInstances: any[]; // List of bot instances.
|
||||||
public minBoot: GBMinInstance;
|
public minBoot: GBMinInstance; // Reference to boot bot.
|
||||||
public wwwroot: string; // .gbui or a static webapp.
|
public wwwroot: string; // .gbui or a static webapp.
|
||||||
public entryPointDialog: string; // To replace default welcome dialog.
|
public entryPointDialog: string; // To replace default welcome dialog.
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue