diff --git a/packages/admin.gbapp/dialogs/AdminDialog.ts b/packages/admin.gbapp/dialogs/AdminDialog.ts index c396e864..5a9acdaa 100644 --- a/packages/admin.gbapp/dialogs/AdminDialog.ts +++ b/packages/admin.gbapp/dialogs/AdminDialog.ts @@ -313,7 +313,7 @@ export class AdminDialog extends IGBDialog { } if (packageName.indexOf('.') !== -1) { - cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${process.env.STORAGE_LIBRARY}/${botId}.gbai/${packageName}`; + cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${GBConfigService.get('STORAGE_LIBRARY')}/${botId}.gbai/${packageName}`; } else { cmd1 = `deployPackage ${packageName}`; } diff --git a/packages/admin.gbapp/services/GBAdminService.ts b/packages/admin.gbapp/services/GBAdminService.ts index 8a274194..2b56c82c 100644 --- a/packages/admin.gbapp/services/GBAdminService.ts +++ b/packages/admin.gbapp/services/GBAdminService.ts @@ -187,8 +187,8 @@ export class GBAdminService implements IGBAdminService { await deployer['cleanupPackage'](min.instance, packageName); } - if (process.env.STORAGE_FILE) { - const path = Path.join(process.env.STORAGE_LIBRARY, gbaiPath); + if (GBConfigService.get('STORAGE_FILE')) { + const path = Path.join(GBConfigService.get('STORAGE_LIBRARY'), gbaiPath); Fs.cpSync(path, localFolder, { errorOnExist: false, force: true, recursive: true}); } else { await deployer['downloadFolder'](min, Path.join('work', `${gbai}`), Path.basename(localFolder)); diff --git a/packages/core.gbapp/dialogs/WelcomeDialog.ts b/packages/core.gbapp/dialogs/WelcomeDialog.ts index d78c4752..ca9d7192 100644 --- a/packages/core.gbapp/dialogs/WelcomeDialog.ts +++ b/packages/core.gbapp/dialogs/WelcomeDialog.ts @@ -36,11 +36,11 @@ import { BotAdapter } from 'botbuilder'; import { WaterfallDialog } from 'botbuilder-dialogs'; -import { GBLog, GBMinInstance, IGBDialog } from 'botlib'; +import { GBMinInstance, IGBDialog } from 'botlib'; import { GBServer } from '../../../src/app.js'; -import { GBConversationalService } from '../services/GBConversationalService.js'; import { Messages } from '../strings.js'; import { GBLogEx } from '../services/GBLogEx.js'; +import { GBConfigService } from '../services/GBConfigService.js'; /** * Dialog for Welcoming people. @@ -65,7 +65,7 @@ export class WelcomeDialog extends IGBDialog { async step => { if ( GBServer.globals.entryPointDialog !== null && - min.instance.botId === process.env.BOT_ID && + min.instance.botId === GBConfigService.get('BOT_ID') && step.context.activity.channelId === 'webchat' ) { return step.replaceDialog(GBServer.globals.entryPointDialog); diff --git a/packages/core.gbapp/services/GBConfigService.ts b/packages/core.gbapp/services/GBConfigService.ts index ae1a570a..38984ad9 100644 --- a/packages/core.gbapp/services/GBConfigService.ts +++ b/packages/core.gbapp/services/GBConfigService.ts @@ -42,7 +42,7 @@ import * as en from 'dotenv-extended'; */ export class GBConfigService { public static getBoolean(value: string): boolean { - return (this.get(value) as unknown) as boolean; + return this.get(value) as unknown as boolean; } public static getServerPort(): string { if (process.env.PORT) { @@ -84,8 +84,11 @@ export class GBConfigService { case 'CLOUD_USERNAME': value = undefined; break; + case 'STORAGE_LIBRARY': + value = `${process.env.HOME}/gbpackages`; + break; case 'BOT_ID': - value = undefined; + value = 'default'; break; case 'CLOUD_PASSWORD': value = undefined; @@ -103,7 +106,7 @@ export class GBConfigService { value = undefined; break; case 'STORAGE_DIALECT': - value = undefined; + value = 'sqlite'; break; case 'STORAGE_FILE': value = './data.db'; @@ -160,7 +163,7 @@ export class GBConfigService { value = true; break; case 'BOT_URL': - value = undefined; + value = 'http://localhost:4242'; break; case 'STORAGE_SERVER': value = undefined; diff --git a/packages/core.gbapp/services/GBCoreService.ts b/packages/core.gbapp/services/GBCoreService.ts index f57f48b2..e7f07af4 100644 --- a/packages/core.gbapp/services/GBCoreService.ts +++ b/packages/core.gbapp/services/GBCoreService.ts @@ -50,6 +50,7 @@ import { GBSecurityPackage } from '../../security.gbapp/index.js'; import { GBWhatsappPackage } from '../../whatsapp.gblib/index.js'; import { GuaribasApplications, GuaribasInstance, GuaribasLog } from '../models/GBModel.js'; import { GBConfigService } from './GBConfigService.js'; +import mkdirp from 'mkdirp'; import { GBAzureDeployerPackage } from '../../azuredeployer.gbapp/index.js'; import { GBSharePointPackage } from '../../sharepoint.gblib/index.js'; import { CollectionUtil } from 'pragmatismo-io-framework'; @@ -109,7 +110,7 @@ export class GBCoreService implements IGBCoreService { constructor() { this.adminService = new GBAdminService(this); } - public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) { } + public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) {} /** * Gets database config and connect to storage. Currently two databases @@ -138,8 +139,8 @@ export class GBCoreService implements IGBCoreService { const logging: boolean | Function = GBConfigService.get('STORAGE_LOGGING') === 'true' ? (str: string): void => { - GBLogEx.info(0, str); - } + GBLogEx.info(0, str); + } : false; const encrypt: boolean = GBConfigService.get('STORAGE_ENCRYPT') === 'true'; @@ -231,7 +232,6 @@ export class GBCoreService implements IGBCoreService { return out; } - /** * Loads all items to start several listeners. */ @@ -426,12 +426,11 @@ ENDPOINT_UPDATE=true let instances: IGBInstance[]; try { instances = await core.loadInstances(); - const group = GBConfigService.get('CLOUD_GROUP')??GBConfigService.get('BOT_ID'); + const group = GBConfigService.get('CLOUD_GROUP') ?? GBConfigService.get('BOT_ID'); if (process.env.ENDPOINT_UPDATE === 'true') { await CollectionUtil.asyncForEach(instances, async instance => { GBLogEx.info(instance.instanceId, `Updating bot endpoint for ${instance.botId}...`); try { - await installationDeployer.updateBotProxy( instance.botId, group, @@ -459,7 +458,10 @@ ENDPOINT_UPDATE=true Try setting STORAGE_SYNC to true in .env file. Error: ${error.message}.` ); } else { - GBLogEx.info(0, `Storage is empty. After collecting storage structure from all .gbapps it will get synced.`); + GBLogEx.info( + 0, + `Storage is empty. After collecting storage structure from all .gbapps it will get synced.` + ); } } else { throw new Error(`Cannot connect to operating storage: ${error.message}.`); @@ -520,7 +522,6 @@ ENDPOINT_UPDATE=true } } - public async createBootInstance( core: GBCoreService, installationDeployer: IGBInstallationDeployer, @@ -529,9 +530,10 @@ ENDPOINT_UPDATE=true return await this.createBootInstanceEx( core, installationDeployer, - proxyAddress, null, - GBConfigService.get('FREE_TIER')); - + proxyAddress, + null, + GBConfigService.get('FREE_TIER') + ); } /** * Creates the first bot instance (boot instance) used to "boot" the server. @@ -548,8 +550,10 @@ ENDPOINT_UPDATE=true ) { GBLogEx.info(0, `Deploying cognitive infrastructure (on the cloud / on premises)...`); try { - const { instance, credentials, subscriptionId, installationDeployer } - = await StartDialog.createBaseInstance(deployer, freeTier); + const { instance, credentials, subscriptionId, installationDeployer } = await StartDialog.createBaseInstance( + deployer, + freeTier + ); installationDeployer['core'] = this; const changedInstance = await installationDeployer['deployFarm2']( proxyAddress, @@ -668,27 +672,26 @@ ENDPOINT_UPDATE=true } public async setConfig(min, name: string, value: any): Promise { - // Handles calls for BASIC persistence on sheet files. - GBLog.info( `Defining Config.xlsx variable ${name}= '${value}'...`); + GBLog.info(`Defining Config.xlsx variable ${name}= '${value}'...`); let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min); const maxLines = 512; - const file = "Config.xlsx"; - const path = DialogKeywords.getGBAIPath(min.botId, `gbot`);; + const file = 'Config.xlsx'; + const path = DialogKeywords.getGBAIPath(min.botId, `gbot`); - let document = await (new SystemKeywords()).internalGetDocument(client, baseUrl, path, file); + let document = await new SystemKeywords().internalGetDocument(client, baseUrl, path, file); - // Creates workbook session that will be discarded. + // Creates book session that will be discarded. - let sheets = await client - .api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`) - .get(); + let sheets = await client.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`).get(); let results = await client - .api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A1:A${maxLines}')`) + .api( + `${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A1:A${maxLines}')` + ) .get(); const rows = results.text; @@ -708,12 +711,12 @@ ENDPOINT_UPDATE=true body.values[0][0] = value; await client - .api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')`) + .api( + `${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')` + ) .patch(body); } - - /** * Get a dynamic param from instance. Dynamic params are defined in Config.xlsx * and loaded into the work folder from comida command. @@ -729,8 +732,7 @@ ENDPOINT_UPDATE=true // Gets .gbot Params from specified bot. if (instance.params) { - - params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params); + params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params); params = GBUtil.caseInsensitive(params); value = params ? params[name] : defaultValue; } @@ -740,7 +742,6 @@ ENDPOINT_UPDATE=true params = GBUtil.caseInsensitive(instance['dataValues']); if (params && !value) { - // Retrieves the value from specified bot instance (no params collection). value = instance['dataValues'][name]; @@ -749,30 +750,26 @@ ENDPOINT_UPDATE=true const minBoot = GBServer.globals.minBoot as any; - if ( - minBoot.instance && - !value && instance.botId != minBoot.instance.botId) { - + if (minBoot.instance && !value && instance.botId != minBoot.instance.botId) { instance = minBoot.instance; - - if(instance.params){ - params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params); + + if (instance.params) { + params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params); params = GBUtil.caseInsensitive(params); value = params ? params[name] : defaultValue; } // If still did not found in boot bot params, try instance fields. - if (!value){ + if (!value) { value = instance['dataValues'][name]; } - if (!value){ + if (!value) { value = instance[name]; } - } } - + if (value === undefined) { value = null; } @@ -786,9 +783,9 @@ ENDPOINT_UPDATE=true if (value && typeof defaultValue === 'number') { return new Number(value ? value : defaultValue ? defaultValue : 0).valueOf(); } - - const ret = value ?? defaultValue; - return ret; + + const ret = value ?? defaultValue; + return ret; } /** @@ -798,7 +795,7 @@ ENDPOINT_UPDATE=true let params = null; const list = []; if (instance.params) { - params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params); + params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params); } Object.keys(params).forEach(e => { @@ -810,5 +807,83 @@ ENDPOINT_UPDATE=true return list; } + public async ensureFolders(instances, deployer: GBDeployer) { + let libraryPath = GBConfigService.get('STORAGE_LIBRARY'); + if (!Fs.existsSync(libraryPath)) { + mkdirp.sync(libraryPath); + } + + + + await this.syncBotStorage(instances, 'default', deployer, libraryPath); + + const files = Fs.readdirSync(libraryPath); + await CollectionUtil.asyncForEach(files, async file => { + + if (file.trim().toLowerCase() !== 'default.gbai'){ + + let botId = file.replace(/\.gbai/, ''); + + await this.syncBotStorage(instances, botId, deployer, libraryPath); + } + }); + } + + private async syncBotStorage(instances: any, botId: any, deployer: GBDeployer, libraryPath: string) { + let instance = instances.find(p => p.botId.toLowerCase().trim() === botId.toLowerCase().trim()); + + if (!instance) { + + GBLog.info(`Importing package ${botId}...`); + + // Creates a bot. + + let mobile = null, + email = null; + + instance = await deployer.deployBlankBot(botId, mobile, email); + const gbaiPath = Path.join(libraryPath, `${botId}.gbai`); + + if (!Fs.existsSync(gbaiPath)) { + + Fs.mkdirSync(gbaiPath, { recursive: true }); + + const base = Path.join(process.env.PWD, 'templates', 'default.gbai'); + + Fs.cpSync(Path.join(base, `default.gbkb`), gbaiPath, { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbot`), gbaiPath, { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbtheme`), gbaiPath, { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbdata`), gbaiPath, { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbdialog`), gbaiPath, { + errorOnExist: false, + force: true, + recursive: true + }); + Fs.cpSync(Path.join(base, `default.gbdrive`), gbaiPath, { + errorOnExist: false, + force: true, + recursive: true + }); + + + } + } + } } diff --git a/packages/core.gbapp/services/GBDeployer.ts b/packages/core.gbapp/services/GBDeployer.ts index c1ac2a58..ca77d4ab 100644 --- a/packages/core.gbapp/services/GBDeployer.ts +++ b/packages/core.gbapp/services/GBDeployer.ts @@ -120,7 +120,7 @@ export class GBDeployer implements IGBDeployer { ); const siteId = process.env.STORAGE_SITE_ID; - const libraryId = process.env.STORAGE_LIBRARY; + const libraryId = GBConfigService.get('STORAGE_LIBRARY'); const client = MicrosoftGraph.Client.init({ authProvider: done => { @@ -222,22 +222,24 @@ export class GBDeployer implements IGBDeployer { const instance = await this.importer.createBotInstance(botId); const bootInstance = GBServer.globals.bootInstance; - // Gets the access token to perform service operations. + if (!GBConfigService.get('STORAGE_FILE')) { + // Gets the access token to perform service operations. - const accessToken = await (GBServer.globals.minBoot.adminService as any)['acquireElevatedToken']( - bootInstance.instanceId, - true - ); + const accessToken = await (GBServer.globals.minBoot.adminService as any)['acquireElevatedToken']( + bootInstance.instanceId, + true + ); - // Creates the MSFT application that will be associated to the bot. + // Creates the MSFT application that will be associated to the bot. - const service = await AzureDeployerService.createInstance(this); - const application = await service.createApplication(accessToken, botId); + const service = await AzureDeployerService.createInstance(this); + const application = await service.createApplication(accessToken, botId); + // Fills new instance base information and get App secret. - // Fills new instance base information and get App secret. + instance.marketplaceId = (application as any).appId; + instance.marketplacePassword = await service.createApplicationSecret(accessToken, (application as any).id); + } - instance.marketplaceId = (application as any).appId; - instance.marketplacePassword = await service.createApplicationSecret(accessToken, (application as any).id); instance.adminPass = GBAdminService.getRndPassword(); instance.title = botId; instance.activationCode = instance.botId.substring(0, 15); @@ -249,10 +251,12 @@ export class GBDeployer implements IGBDeployer { // Saves bot information to the store. await this.core.saveInstance(instance); - + if (!GBConfigService.get('STORAGE_FILE')) { + await this.deployBotOnAzure(instance, GBServer.globals.publicAddress); + } // Creates remaining objects on the cloud and updates instance information. - return await this.deployBotFull(instance, GBServer.globals.publicAddress); + return instance; } /** @@ -267,7 +271,7 @@ export class GBDeployer implements IGBDeployer { /** * Performs all tasks of deploying a new bot on the cloud. */ - public async deployBotFull(instance: IGBInstance, publicAddress: string): Promise { + public async deployBotOnAzure(instance: IGBInstance, publicAddress: string): Promise { // Reads base configuration from environent file. const service = await AzureDeployerService.createInstance(this); @@ -411,7 +415,7 @@ export class GBDeployer implements IGBDeployer { public async deployBotFromLocalPath(localPath: string, publicAddress: string): Promise { const packageName = Path.basename(localPath); const instance = await this.importer.importIfNotExistsBotPackage(undefined, packageName, localPath); - await this.deployBotFull(instance, publicAddress); + await this.deployBotOnAzure(instance, publicAddress); } /** diff --git a/packages/core.gbapp/services/GBMinService.ts b/packages/core.gbapp/services/GBMinService.ts index 78556c36..07427417 100644 --- a/packages/core.gbapp/services/GBMinService.ts +++ b/packages/core.gbapp/services/GBMinService.ts @@ -42,10 +42,11 @@ import { FacebookAdapter } from 'botbuilder-adapter-facebook'; import mkdirp from 'mkdirp'; import Fs from 'fs'; import arrayBufferToBuffer from 'arraybuffer-to-buffer'; -import { v2 as webdav } from 'webdav-server'; import { NlpManager } from 'node-nlp'; import Koa from 'koa'; +import { v2 as webdav } from 'webdav-server'; import { createRpcServer } from '@push-rpc/core'; +import { start as startRouter } from '../../../packages/core.gbapp/services/router/bridge.js'; import wash from 'washyourmouthoutwithsoap'; import { AutoSaveStateMiddleware, @@ -172,6 +173,9 @@ export class GBMinService { await CollectionUtil.asyncForEach( instances, (async instance => { + + startRouter(GBServer.globals.server, instance.botId); + try { GBLog.info(`Mounting ${instance.botId}...`); await this['mountBot'](instance); @@ -256,7 +260,7 @@ export class GBMinService { // Serves individual URL for each bot conversational interface. - await this.deployer['deployPackage2'](min, user, 'packages/default.gbtheme'); + await this.deployer['deployPackage2'](min, user, 'templates/default.gbai/default.gbtheme'); // Install per bot deployed packages. @@ -280,7 +284,7 @@ export class GBMinService { const gbai = DialogKeywords.getGBAIPath(min.botId); let dir = `work/${gbai}/cache`; const botId = gbai.replace(/\.[^/.]+$/, ''); - + if (!Fs.existsSync(dir)) { mkdirp.sync(dir); } @@ -317,12 +321,12 @@ export class GBMinService { mkdirp.sync(dir); } - if (process.env.STORAGE_FILE) { - dir = Path.join(process.env.STORAGE_LIBRARY, 'work', gbai); + if (GBConfigService.get('STORAGE_FILE')) { + dir = Path.join(GBConfigService.get('STORAGE_LIBRARY'), 'work', gbai); - const server = new webdav.WebDAVServer(); + const server = GBServer.globals.webDavServer; server.setFileSystem(`/${botId}`, new webdav.PhysicalFileSystem(dir), success => { - server.start(() => console.log('WEBDAV READY')); + GBLogEx.info(1, `WebDav for ${botId} loaded.`); }); } // Loads Named Entity data for this bot. @@ -691,8 +695,8 @@ export class GBMinService { color2: this.core.getParam(instance, 'Color2', null) }; - if (process.env.STORAGE_FILE) { - config['domain'] = `http://localhost:${process.env.PORT}/directline`; + if (GBConfigService.get('STORAGE_FILE')) { + config['domain'] = `http://localhost:${process.env.PORT}/directline/${botId}`; } else { const webchatTokenContainer = await this.getWebchatToken(instance); config['conversationId']= webchatTokenContainer.conversationId, @@ -763,7 +767,7 @@ export class GBMinService { ? instance.marketplacePassword : GBConfigService.get('MARKETPLACE_SECRET') }; - if (process.env.STORAGE_FILE) { + if (GBConfigService.get('STORAGE_FILE')) { config['clientOptions'] = { baseUri: `http://localhost:${process.env.PORT}` }; } @@ -830,8 +834,6 @@ export class GBMinService { let url = `/api/messages/${instance.botId}`; GBServer.globals.server.post(url, receiver); - url = `/api/messages`; - GBServer.globals.server.post(url, receiver); // NLP Manager. @@ -843,6 +845,10 @@ export class GBMinService { GBServer.globals.minBoot.instance.marketplaceId = GBConfigService.get('MARKETPLACE_ID'); GBServer.globals.minBoot.instance.marketplacePassword = GBConfigService.get('MARKETPLACE_SECRET'); } + else{ + url = `/api/messages`; + GBServer.globals.server.post(url, receiver); + } if (min.instance.facebookWorkplaceVerifyToken) { min['fbAdapter'] = new FacebookAdapter({ @@ -1192,7 +1198,7 @@ export class GBMinService { }; try { - if (process.env.STORAGE_FILE) { + if (GBConfigService.get('STORAGE_FILE')) { const context = adapter['createContext'](req); context['_activity'] = context.activity.body; await handler(context); diff --git a/packages/core.gbapp/services/router/bridge.ts b/packages/core.gbapp/services/router/bridge.ts index 25ed4d34..2ea9e713 100644 --- a/packages/core.gbapp/services/router/bridge.ts +++ b/packages/core.gbapp/services/router/bridge.ts @@ -11,7 +11,7 @@ const conversationsCleanupInterval = 10000; const conversations: { [key: string]: IConversation } = {}; const botDataStore: { [key: string]: IBotData } = {}; -export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRequired = true): express.Router => { +export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRequired = true, botId): express.Router => { const router = express.Router(); router.use(bodyParser.json()); // for parsing application/json @@ -22,8 +22,9 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization, x-ms-bot-agent'); next(); }); + // CLIENT ENDPOINT - router.options('/directline', (req, res) => { + router.options(`/directline/${botId}/`, (req, res) => { res.status(200).end(); }); @@ -53,7 +54,7 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe }; router.post('/v3/directline/conversations',reqs ); - router.post('/directline/conversations',reqs ); + router.post(`/directline/${botId}/conversations`,reqs ); // Reconnect API router.get('/v3/directline/conversations/:conversationId', (req, res) => { @@ -69,7 +70,7 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe }); // Gets activities from store (local history array for now) - router.get('/directline/conversations/:conversationId/activities', (req, res) => { + router.get(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => { const watermark = req.query.watermark && req.query.watermark !== 'null' ? Number(req.query.watermark) : 0; const conversation = getConversation(req.params.conversationId, conversationInitRequired); @@ -95,7 +96,7 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe }); // Sends message to bot. Assumes message activities - router.post('/directline/conversations/:conversationId/activities', (req, res) => { + router.post(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => { const incomingActivity = req.body; // Make copy of activity. Add required fields const activity = createMessageActivity(incomingActivity, serviceUrl, req.params.conversationId); @@ -209,11 +210,11 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe * @param conversationInitRequired Requires that a conversation is initialized before it is accessed, returning a 400 * when not the case. If set to false, a new conversation reference is created on the fly. This is true by default. */ -export const initializeRoutes = (app: express.Express, port: number, botUrl: string, conversationInitRequired = true) => { +export const initializeRoutes = (app: express.Express, port: number, botUrl: string, conversationInitRequired = true, botId) => { conversationsCleanup(); const directLineEndpoint = `http://127.0.0.1:${port}`; - const router = getRouter(directLineEndpoint, botUrl, conversationInitRequired); + const router = getRouter(directLineEndpoint, botUrl, conversationInitRequired, botId); app.use(router); console.log(`Routing messages to bot on ${botUrl}`); @@ -272,9 +273,9 @@ const setPrivateConversationData = (req: express.Request, res: express.Response) res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body)); }; -export const start = (server)=>{ +export const start = (server, botId)=>{ - initializeRoutes(server, Number(process.env.PORT), `http://127.0.0.1:${process.env.PORT}/api/messages`); + initializeRoutes(server, Number(process.env.PORT), `http://127.0.0.1:${process.env.PORT}/api/messages/${botId}`, null, botId); } const deleteStateForUser = (req: express.Request, res: express.Response) => { diff --git a/packages/default.gbapp.gbignore/.gitkeep b/packages/default.gbapp.gbignore/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/default.gbtest/first-test.xlsx b/packages/default.gbtest/first-test.xlsx deleted file mode 100644 index a6bad648..00000000 Binary files a/packages/default.gbtest/first-test.xlsx and /dev/null differ diff --git a/packages/kb.gbapp/services/KBService.ts b/packages/kb.gbapp/services/KBService.ts index 7829c3f2..32861cbc 100644 --- a/packages/kb.gbapp/services/KBService.ts +++ b/packages/kb.gbapp/services/KBService.ts @@ -1370,7 +1370,7 @@ export class KBService implements IGBKBService { await this.importKbPackage(min, localPath, p, instance); GBDeployer.mountGBKBAssets(packageName, min.botId, localPath); - if (!process.env.STORAGE_FILE) { + if (!GBConfigService.get('STORAGE_FILE')) { const service = await AzureDeployerService.createInstance(deployer); const searchIndex = instance.searchIndex ? instance.searchIndex : GBServer.globals.minBoot.instance.searchIndex; await deployer.rebuildIndex(instance, service.getKBSearchSchema(searchIndex)); diff --git a/src/RootData.ts b/src/RootData.ts index 62e676ad..c026333f 100644 --- a/src/RootData.ts +++ b/src/RootData.ts @@ -65,4 +65,5 @@ export class RootData { public dbg; public img; indexSemaphore: any; + public webDavServer; } diff --git a/src/app.ts b/src/app.ts index 8806eb3a..1c2c3773 100644 --- a/src/app.ts +++ b/src/app.ts @@ -40,8 +40,7 @@ import bodyParser from 'body-parser'; import { GBLog, GBMinInstance, IGBCoreService, IGBInstance } from 'botlib'; import child_process from 'child_process'; import express from 'express'; -import {start as startRouter} from '../packages/core.gbapp/services/router/bridge.js' - +import { v2 as webdav } from 'webdav-server'; import fs from 'fs'; import http from 'http'; import httpProxy from 'http-proxy'; @@ -89,7 +88,7 @@ export class GBServer { const server = express(); this.initEndpointsDocs(server); - startRouter(server); + GBServer.globals.server = server; GBServer.globals.httpsServer = null; @@ -105,6 +104,8 @@ export class GBServer { GBServer.globals.debuggers = []; GBServer.globals.users = []; GBServer.globals.indexSemaphore = new Mutex(); + GBServer.globals.webDavServer = new webdav.WebDAVServer(); + GBServer.globals.webDavServer.start(); server.use(bodyParser.json()); server.use(bodyParser.json({ limit: '1mb' })); @@ -121,7 +122,10 @@ export class GBServer { }); process.on('uncaughtException', (err, p) => { - GBLogEx.error(0, `GBEXCEPTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}`); + GBLogEx.error( + 0, + `GBEXCEPTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}` + ); }); process.on('unhandledRejection', (err, p) => { @@ -134,7 +138,10 @@ export class GBServer { } if (!bypass) { - GBLogEx.error(0,`GBREJECTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}`); + GBLogEx.error( + 0, + `GBREJECTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}` + ); } }); @@ -150,7 +157,7 @@ export class GBServer { (async () => { try { GBLogEx.info(0, `Now accepting connections on ${port}...`); - + process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; // Reads basic configuration, initialize minimal services. @@ -186,7 +193,6 @@ export class GBServer { } else if (GBConfigService.get('STORAGE_FILE')) { await core.initStorage(); } else { - runOnce = true; [GBServer.globals.bootInstance, azureDeployer] = await core['createBootInstanceEx']( core, null, @@ -194,6 +200,7 @@ export class GBServer { deployer, GBConfigService.get('FREE_TIER') ); + await core.saveInstance(GBServer.globals.bootInstance); } core.ensureAdminIsSecured(); @@ -207,10 +214,6 @@ export class GBServer { await deployer.deployPackages(core, server, GBServer.globals.appPackages); await core.syncDatabaseStructure(); - if (runOnce) { - await core.saveInstance(GBServer.globals.bootInstance); - } - // Deployment of local applications for the first time. if (GBConfigService.get('DISABLE_WEB') !== 'true') { @@ -224,23 +227,27 @@ export class GBServer { GBServer.globals.publicAddress ); - if (instances.length === 0) { - const instance = await importer.importIfNotExistsBotPackage( - GBConfigService.get('BOT_ID'), - 'boot.gbot', - 'packages/boot.gbot', - GBServer.globals.bootInstance - ); + if (instances. length === 0) { + if (!GBConfigService.get('STORAGE_FILE')) { + const instance = await importer.importIfNotExistsBotPackage( + GBConfigService.get('BOT_ID'), + 'boot.gbot', + 'packages/boot.gbot', + GBServer.globals.bootInstance + ); - instances.push(instance); - GBServer.globals.minBoot.instance = instances[0]; - GBServer.globals.bootInstance = instances[0]; - await deployer.deployBotFull(instance, GBServer.globals.publicAddress); + instances.push(instance); + GBServer.globals.minBoot.instance = instances[0]; + GBServer.globals.bootInstance = instances[0]; + await deployer.deployBotOnAzure(instance, GBServer.globals.publicAddress); - // Runs the search even with empty content to create structure. + // Runs the search even with empty content to create structure. - await azureDeployer['runSearch'](instance); + await azureDeployer['runSearch'](instance); + } } + + await core['ensureFolders'](instances, deployer); GBServer.globals.bootInstance = instances[0]; @@ -251,7 +258,7 @@ export class GBServer { const minService: GBMinService = new GBMinService(core, conversationalService, adminService, deployer); GBServer.globals.minService = minService; await minService.buildMin(instances); - + server.all('*', async (req, res, next) => { const host = req.headers.host; diff --git a/src/util.ts b/src/util.ts index fb123469..96fcf256 100644 --- a/src/util.ts +++ b/src/util.ts @@ -36,6 +36,7 @@ import * as YAML from 'yaml'; import SwaggerClient from 'swagger-client'; import Fs from 'fs'; +import { GBConfigService } from '../packages/core.gbapp/services/GBConfigService.js'; export class GBUtil { public static repeat(chr, count) { @@ -69,14 +70,14 @@ export class GBUtil { public static async getDirectLineClient(min) { let config = { - url: `http://127.0.0.1:${process.env.port}/api/messages`, + url: `http://127.0.0.1:${GBConfigService.get('PORT')}/api/messages`, spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')), requestInterceptor: req => { req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`; } }; - if (process.env.STORAGE_FILE) { - config['spec'].servers = [{ url: `http://127.0.0.1:${process.env.PORT}/api/messages` }]; + if (GBConfigService.get('STORAGE_FILE')) { + config['spec'].servers = [{ url: `http://127.0.0.1:${GBConfigService.get('PORT')}/api/messages` }]; config['openapi'] = '3.0.0'; } return await new SwaggerClient(config); diff --git a/packages/default.gbdialog/bot.vbs.gbignore b/templates/default.gbai/default.gbdialog/bot.vbs.gbignore similarity index 100% rename from packages/default.gbdialog/bot.vbs.gbignore rename to templates/default.gbai/default.gbdialog/bot.vbs.gbignore diff --git a/packages/default.gbdialog/delivery.vbs.gbignore b/templates/default.gbai/default.gbdialog/delivery.vbs.gbignore similarity index 100% rename from packages/default.gbdialog/delivery.vbs.gbignore rename to templates/default.gbai/default.gbdialog/delivery.vbs.gbignore diff --git a/packages/default.gbdialog/find-on-excel.vbs b/templates/default.gbai/default.gbdialog/find-on-excel.vbs similarity index 100% rename from packages/default.gbdialog/find-on-excel.vbs rename to templates/default.gbai/default.gbdialog/find-on-excel.vbs diff --git a/packages/default.gbdialog/find-or-talk.vbs.gbignore b/templates/default.gbai/default.gbdialog/find-or-talk.vbs.gbignore similarity index 100% rename from packages/default.gbdialog/find-or-talk.vbs.gbignore rename to templates/default.gbai/default.gbdialog/find-or-talk.vbs.gbignore diff --git a/packages/default.gbdialog/get-payment.vbs.gbignore b/templates/default.gbai/default.gbdialog/get-payment.vbs.gbignore similarity index 100% rename from packages/default.gbdialog/get-payment.vbs.gbignore rename to templates/default.gbai/default.gbdialog/get-payment.vbs.gbignore diff --git a/packages/default.gbdialog/get-set-excel.vbs b/templates/default.gbai/default.gbdialog/get-set-excel.vbs similarity index 100% rename from packages/default.gbdialog/get-set-excel.vbs rename to templates/default.gbai/default.gbdialog/get-set-excel.vbs diff --git a/packages/default.gbdialog/get-stock.vbs.gbignore b/templates/default.gbai/default.gbdialog/get-stock.vbs.gbignore similarity index 100% rename from packages/default.gbdialog/get-stock.vbs.gbignore rename to templates/default.gbai/default.gbdialog/get-stock.vbs.gbignore diff --git a/packages/default.gbdialog/http-get-and-post.vbs b/templates/default.gbai/default.gbdialog/http-get-and-post.vbs similarity index 100% rename from packages/default.gbdialog/http-get-and-post.vbs rename to templates/default.gbai/default.gbdialog/http-get-and-post.vbs diff --git a/packages/default.gbdialog/lab.vbs.gbignore b/templates/default.gbai/default.gbdialog/lab.vbs.gbignore similarity index 100% rename from packages/default.gbdialog/lab.vbs.gbignore rename to templates/default.gbai/default.gbdialog/lab.vbs.gbignore diff --git a/packages/default.gbdialog/save-on-excel.vbs.gbignore b/templates/default.gbai/default.gbdialog/save-on-excel.vbs.gbignore similarity index 100% rename from packages/default.gbdialog/save-on-excel.vbs.gbignore rename to templates/default.gbai/default.gbdialog/save-on-excel.vbs.gbignore diff --git a/packages/default.gbdialog/sys-bot-farm-creation.vbs.gbignore b/templates/default.gbai/default.gbdialog/sys-bot-farm-creation.vbs.gbignore similarity index 100% rename from packages/default.gbdialog/sys-bot-farm-creation.vbs.gbignore rename to templates/default.gbai/default.gbdialog/sys-bot-farm-creation.vbs.gbignore diff --git a/packages/default.gbdialog/templates.vbs b/templates/default.gbai/default.gbdialog/templates.vbs similarity index 100% rename from packages/default.gbdialog/templates.vbs rename to templates/default.gbai/default.gbdialog/templates.vbs diff --git a/packages/default.gbdialog/translator.gbignore b/templates/default.gbai/default.gbdialog/translator.gbignore similarity index 100% rename from packages/default.gbdialog/translator.gbignore rename to templates/default.gbai/default.gbdialog/translator.gbignore diff --git a/packages/default.gbkb/draft.md b/templates/default.gbai/default.gbkb/draft.md similarity index 100% rename from packages/default.gbkb/draft.md rename to templates/default.gbai/default.gbkb/draft.md diff --git a/packages/default.gbkb/package.json b/templates/default.gbai/default.gbkb/package.json similarity index 100% rename from packages/default.gbkb/package.json rename to templates/default.gbai/default.gbkb/package.json diff --git a/packages/default.gbkb/pages/about.md b/templates/default.gbai/default.gbkb/pages/about.md similarity index 100% rename from packages/default.gbkb/pages/about.md rename to templates/default.gbai/default.gbkb/pages/about.md diff --git a/packages/default.gbkb/subjects.json b/templates/default.gbai/default.gbkb/subjects.json similarity index 100% rename from packages/default.gbkb/subjects.json rename to templates/default.gbai/default.gbkb/subjects.json diff --git a/packages/default.gbkb/subjects/bots-ai.png b/templates/default.gbai/default.gbkb/subjects/bots-ai.png similarity index 100% rename from packages/default.gbkb/subjects/bots-ai.png rename to templates/default.gbai/default.gbkb/subjects/bots-ai.png diff --git a/packages/default.gbkb/subjects/cortana.png b/templates/default.gbai/default.gbkb/subjects/cortana.png similarity index 100% rename from packages/default.gbkb/subjects/cortana.png rename to templates/default.gbai/default.gbkb/subjects/cortana.png diff --git a/packages/default.gbkb/subjects/general-bots.png b/templates/default.gbai/default.gbkb/subjects/general-bots.png similarity index 100% rename from packages/default.gbkb/subjects/general-bots.png rename to templates/default.gbai/default.gbkb/subjects/general-bots.png diff --git a/packages/default.gbkb/subjects/msdynamics.png b/templates/default.gbai/default.gbkb/subjects/msdynamics.png similarity index 100% rename from packages/default.gbkb/subjects/msdynamics.png rename to templates/default.gbai/default.gbkb/subjects/msdynamics.png diff --git a/packages/default.gbkb/subjects/msproject.png b/templates/default.gbai/default.gbkb/subjects/msproject.png similarity index 100% rename from packages/default.gbkb/subjects/msproject.png rename to templates/default.gbai/default.gbkb/subjects/msproject.png diff --git a/packages/default.gbkb/subjects/office365.png b/templates/default.gbai/default.gbkb/subjects/office365.png similarity index 100% rename from packages/default.gbkb/subjects/office365.png rename to templates/default.gbai/default.gbkb/subjects/office365.png diff --git a/packages/default.gbkb/subjects/powerbi.png b/templates/default.gbai/default.gbkb/subjects/powerbi.png similarity index 100% rename from packages/default.gbkb/subjects/powerbi.png rename to templates/default.gbai/default.gbkb/subjects/powerbi.png diff --git a/packages/default.gbkb/subjects/produtividade.png b/templates/default.gbai/default.gbkb/subjects/produtividade.png similarity index 100% rename from packages/default.gbkb/subjects/produtividade.png rename to templates/default.gbai/default.gbkb/subjects/produtividade.png diff --git a/packages/default.gbkb/subjects/sharepoint.png b/templates/default.gbai/default.gbkb/subjects/sharepoint.png similarity index 100% rename from packages/default.gbkb/subjects/sharepoint.png rename to templates/default.gbai/default.gbkb/subjects/sharepoint.png diff --git a/packages/default.gbkb/subjects/skype.png b/templates/default.gbai/default.gbkb/subjects/skype.png similarity index 100% rename from packages/default.gbkb/subjects/skype.png rename to templates/default.gbai/default.gbkb/subjects/skype.png diff --git a/packages/default.gbkb/subjects/sobre.png b/templates/default.gbai/default.gbkb/subjects/sobre.png similarity index 100% rename from packages/default.gbkb/subjects/sobre.png rename to templates/default.gbai/default.gbkb/subjects/sobre.png diff --git a/packages/default.gbkb/tabular/common-goodbye.tsv b/templates/default.gbai/default.gbkb/tabular/common-goodbye.tsv similarity index 100% rename from packages/default.gbkb/tabular/common-goodbye.tsv rename to templates/default.gbai/default.gbkb/tabular/common-goodbye.tsv diff --git a/packages/default.gbkb/tabular/common-hello.tsv b/templates/default.gbai/default.gbkb/tabular/common-hello.tsv similarity index 100% rename from packages/default.gbkb/tabular/common-hello.tsv rename to templates/default.gbai/default.gbkb/tabular/common-hello.tsv diff --git a/packages/default.gbkb/tabular/common-persona.tsv b/templates/default.gbai/default.gbkb/tabular/common-persona.tsv similarity index 100% rename from packages/default.gbkb/tabular/common-persona.tsv rename to templates/default.gbai/default.gbkb/tabular/common-persona.tsv diff --git a/packages/default.gbkb/tabular/min.tsv b/templates/default.gbai/default.gbkb/tabular/min.tsv similarity index 100% rename from packages/default.gbkb/tabular/min.tsv rename to templates/default.gbai/default.gbkb/tabular/min.tsv diff --git a/packages/default.gbkb/videos/placeholder b/templates/default.gbai/default.gbkb/videos/placeholder similarity index 100% rename from packages/default.gbkb/videos/placeholder rename to templates/default.gbai/default.gbkb/videos/placeholder diff --git a/packages/default.gbtheme/css/App.css b/templates/default.gbai/default.gbtheme/css/App.css similarity index 100% rename from packages/default.gbtheme/css/App.css rename to templates/default.gbai/default.gbtheme/css/App.css diff --git a/packages/default.gbtheme/css/ChatPane.css b/templates/default.gbai/default.gbtheme/css/ChatPane.css similarity index 100% rename from packages/default.gbtheme/css/ChatPane.css rename to templates/default.gbai/default.gbtheme/css/ChatPane.css diff --git a/packages/default.gbtheme/css/Content.css b/templates/default.gbai/default.gbtheme/css/Content.css similarity index 100% rename from packages/default.gbtheme/css/Content.css rename to templates/default.gbai/default.gbtheme/css/Content.css diff --git a/packages/default.gbtheme/css/Footer.css b/templates/default.gbai/default.gbtheme/css/Footer.css similarity index 100% rename from packages/default.gbtheme/css/Footer.css rename to templates/default.gbai/default.gbtheme/css/Footer.css diff --git a/packages/default.gbtheme/css/GifPlayer.css b/templates/default.gbai/default.gbtheme/css/GifPlayer.css similarity index 100% rename from packages/default.gbtheme/css/GifPlayer.css rename to templates/default.gbai/default.gbtheme/css/GifPlayer.css diff --git a/packages/default.gbtheme/css/MediaPlayer.css b/templates/default.gbai/default.gbtheme/css/MediaPlayer.css similarity index 100% rename from packages/default.gbtheme/css/MediaPlayer.css rename to templates/default.gbai/default.gbtheme/css/MediaPlayer.css diff --git a/packages/default.gbtheme/css/NavBar.css b/templates/default.gbai/default.gbtheme/css/NavBar.css similarity index 100% rename from packages/default.gbtheme/css/NavBar.css rename to templates/default.gbai/default.gbtheme/css/NavBar.css diff --git a/packages/default.gbtheme/css/SideBarMenu.css b/templates/default.gbai/default.gbtheme/css/SideBarMenu.css similarity index 100% rename from packages/default.gbtheme/css/SideBarMenu.css rename to templates/default.gbai/default.gbtheme/css/SideBarMenu.css diff --git a/packages/default.gbtheme/css/index.css b/templates/default.gbai/default.gbtheme/css/index.css similarity index 100% rename from packages/default.gbtheme/css/index.css rename to templates/default.gbai/default.gbtheme/css/index.css diff --git a/packages/default.gbtheme/css/webchat-style.json b/templates/default.gbai/default.gbtheme/css/webchat-style.json similarity index 100% rename from packages/default.gbtheme/css/webchat-style.json rename to templates/default.gbai/default.gbtheme/css/webchat-style.json diff --git a/packages/default.gbtheme/images/bot-logo-chat.png b/templates/default.gbai/default.gbtheme/images/bot-logo-chat.png similarity index 100% rename from packages/default.gbtheme/images/bot-logo-chat.png rename to templates/default.gbai/default.gbtheme/images/bot-logo-chat.png diff --git a/packages/default.gbtheme/images/bot-logo.png b/templates/default.gbai/default.gbtheme/images/bot-logo.png similarity index 100% rename from packages/default.gbtheme/images/bot-logo.png rename to templates/default.gbai/default.gbtheme/images/bot-logo.png diff --git a/packages/default.gbtheme/images/bot-tv-on.png b/templates/default.gbai/default.gbtheme/images/bot-tv-on.png similarity index 100% rename from packages/default.gbtheme/images/bot-tv-on.png rename to templates/default.gbai/default.gbtheme/images/bot-tv-on.png diff --git a/packages/default.gbtheme/images/bot-tv-on2.png b/templates/default.gbai/default.gbtheme/images/bot-tv-on2.png similarity index 100% rename from packages/default.gbtheme/images/bot-tv-on2.png rename to templates/default.gbai/default.gbtheme/images/bot-tv-on2.png diff --git a/packages/default.gbtheme/images/bot-tv.png b/templates/default.gbai/default.gbtheme/images/bot-tv.png similarity index 100% rename from packages/default.gbtheme/images/bot-tv.png rename to templates/default.gbai/default.gbtheme/images/bot-tv.png diff --git a/packages/default.gbtheme/images/chat-background.png b/templates/default.gbai/default.gbtheme/images/chat-background.png similarity index 100% rename from packages/default.gbtheme/images/chat-background.png rename to templates/default.gbai/default.gbtheme/images/chat-background.png diff --git a/packages/default.gbtheme/images/chat-header-logo.png b/templates/default.gbai/default.gbtheme/images/chat-header-logo.png similarity index 100% rename from packages/default.gbtheme/images/chat-header-logo.png rename to templates/default.gbai/default.gbtheme/images/chat-header-logo.png diff --git a/packages/default.gbtheme/images/chat-header.png b/templates/default.gbai/default.gbtheme/images/chat-header.png similarity index 100% rename from packages/default.gbtheme/images/chat-header.png rename to templates/default.gbai/default.gbtheme/images/chat-header.png diff --git a/packages/default.gbtheme/images/general-bot-background.jpg b/templates/default.gbai/default.gbtheme/images/general-bot-background.jpg similarity index 100% rename from packages/default.gbtheme/images/general-bot-background.jpg rename to templates/default.gbai/default.gbtheme/images/general-bot-background.jpg diff --git a/packages/default.gbtheme/images/logo-Pragmatismo.png b/templates/default.gbai/default.gbtheme/images/logo-Pragmatismo.png similarity index 100% rename from packages/default.gbtheme/images/logo-Pragmatismo.png rename to templates/default.gbai/default.gbtheme/images/logo-Pragmatismo.png diff --git a/packages/default.gbtheme/images/logo.jpg b/templates/default.gbai/default.gbtheme/images/logo.jpg similarity index 100% rename from packages/default.gbtheme/images/logo.jpg rename to templates/default.gbai/default.gbtheme/images/logo.jpg diff --git a/packages/default.gbtheme/images/logo.png b/templates/default.gbai/default.gbtheme/images/logo.png similarity index 100% rename from packages/default.gbtheme/images/logo.png rename to templates/default.gbai/default.gbtheme/images/logo.png diff --git a/packages/default.gbtheme/images/pragmatismo-logo.png b/templates/default.gbai/default.gbtheme/images/pragmatismo-logo.png similarity index 100% rename from packages/default.gbtheme/images/pragmatismo-logo.png rename to templates/default.gbai/default.gbtheme/images/pragmatismo-logo.png diff --git a/packages/default.gbtheme/images/pragmatismo-powered-by.png b/templates/default.gbai/default.gbtheme/images/pragmatismo-powered-by.png similarity index 100% rename from packages/default.gbtheme/images/pragmatismo-powered-by.png rename to templates/default.gbai/default.gbtheme/images/pragmatismo-powered-by.png diff --git a/packages/default.gbtheme/images/projector-background.jpg b/templates/default.gbai/default.gbtheme/images/projector-background.jpg similarity index 100% rename from packages/default.gbtheme/images/projector-background.jpg rename to templates/default.gbai/default.gbtheme/images/projector-background.jpg diff --git a/packages/default.gbtheme/images/projetor_tela.png b/templates/default.gbai/default.gbtheme/images/projetor_tela.png similarity index 100% rename from packages/default.gbtheme/images/projetor_tela.png rename to templates/default.gbai/default.gbtheme/images/projetor_tela.png diff --git a/packages/default.gbtheme/images/screen.png b/templates/default.gbai/default.gbtheme/images/screen.png similarity index 100% rename from packages/default.gbtheme/images/screen.png rename to templates/default.gbai/default.gbtheme/images/screen.png diff --git a/packages/default.gbtheme/images/tela-01.png b/templates/default.gbai/default.gbtheme/images/tela-01.png similarity index 100% rename from packages/default.gbtheme/images/tela-01.png rename to templates/default.gbai/default.gbtheme/images/tela-01.png diff --git a/packages/default.gbtheme/package.json b/templates/default.gbai/default.gbtheme/package.json similarity index 100% rename from packages/default.gbtheme/package.json rename to templates/default.gbai/default.gbtheme/package.json