From d3769e5bf347a8d8ed595ad6bf7d6cef8e322df6 Mon Sep 17 00:00:00 2001 From: Rodrigo Rodriguez Date: Fri, 5 Aug 2022 00:10:23 -0300 Subject: [PATCH] new(basic.gblib): PUT keyword. --- packages/basic.gblib/dialogs/HearDialog.ts | 20 +++-- .../basic.gblib/services/DialogKeywords.ts | 12 ++- packages/basic.gblib/services/GBVMService.ts | 23 ++++-- .../basic.gblib/services/SystemKeywords.ts | 82 +++++++++++++------ packages/core.gbapp/services/GBMinService.ts | 4 + 5 files changed, 101 insertions(+), 40 deletions(-) diff --git a/packages/basic.gblib/dialogs/HearDialog.ts b/packages/basic.gblib/dialogs/HearDialog.ts index e98f8f4a..05cdb43c 100644 --- a/packages/basic.gblib/dialogs/HearDialog.ts +++ b/packages/basic.gblib/dialogs/HearDialog.ts @@ -52,11 +52,10 @@ export class HearDialog { private static async downloadAttachmentAndWrite(attachment) { - // Retrieve the attachment via the attachment's contentUrl. + const url = attachment.contentUrl; - - // Local file path for the bot to save the attachment. - const localFileName = Path.join(__dirname, attachment.name); + const localFolder = Path.join('work', 'dev-rodriguez.gbai', 'uploads'); + const localFileName = Path.join(localFolder, attachment.name); try { // arraybuffer is necessary for images @@ -135,17 +134,17 @@ export class HearDialog { if (step.activeDialog.state.options['kind'] === "file") { // Prepare Promises to download each attachment and then execute each Promise. - const promises = step.context.activity.attachments.map(HearDialog.downloadAttachmentAndWrite); + const promises = step.context.activity.attachments.map( + HearDialog.downloadAttachmentAndWrite); const successfulSaves = await Promise.all(promises); async function replyForReceivedAttachments(localAttachmentData) { if (localAttachmentData) { // Because the TurnContext was bound to this function, the bot can call // `TurnContext.sendActivity` via `this.sendActivity`; - await this.sendActivity(`Attachment "${localAttachmentData.fileName}" ` + - `has been received and saved to "${localAttachmentData.localPath}".`); + await this.sendActivity(`Upload OK.`); } else { - await this.sendActivity('Attachment was not successfully saved to disk.'); + await this.sendActivity('Error uploading file. Please, start again.'); } } @@ -153,6 +152,11 @@ export class HearDialog { // The current TurnContext is bound so `replyForReceivedAttachments` can also send replies. const replyPromises = successfulSaves.map(replyForReceivedAttachments.bind(step.context)); await Promise.all(replyPromises); + + result = { + data: fs.readFileSync(successfulSaves[0].localPath), + filename: successfulSaves[0].fileName + }; } else if (step.activeDialog.state.options['kind'] === "boolean") { diff --git a/packages/basic.gblib/services/DialogKeywords.ts b/packages/basic.gblib/services/DialogKeywords.ts index 9bc25d92..ecf11e82 100644 --- a/packages/basic.gblib/services/DialogKeywords.ts +++ b/packages/basic.gblib/services/DialogKeywords.ts @@ -407,8 +407,16 @@ export class DialogKeywords { } - public getCoded(text){ - return Buffer.from(text).toString("base64"); + public getCoded(value){ + + // Checks if it is a GB FILE object. + + if (value.data && value.filename) + { + value = value.data; + } + + return Buffer.from(value).toString("base64"); } /** diff --git a/packages/basic.gblib/services/GBVMService.ts b/packages/basic.gblib/services/GBVMService.ts index 0f3b1ff3..9c1c4d41 100644 --- a/packages/basic.gblib/services/GBVMService.ts +++ b/packages/basic.gblib/services/GBVMService.ts @@ -79,7 +79,7 @@ export class GBVMService extends GBService { const vbsFile = filename.substr(0, filename.indexOf('docx')) + 'vbs'; const fullVbsFile = urlJoin(folder, vbsFile); const docxStat = fs.statSync(urlJoin(folder, wordFile)); - const interval = 30000; // If compiled is older 30 seconds, then recompile. + const interval = 3000; // If compiled is older 30 seconds, then recompile. let writeVBS = true; if (fs.existsSync(fullVbsFile)) { const vbsStat = fs.statSync(fullVbsFile); @@ -324,9 +324,7 @@ export class GBVMService extends GBService { }); code = code.replace(/(\w+)\s*\=\s*get\s(.*)/gi, ($0, $1, $2, $3) => { - if ($2.indexOf('http') !== -1) { - return `${$1} = sys().getByHttp (${$2}, headers, httpUsername, httpPs)`; - } else { + const count = ($2.match(/\,/g) || []).length; const values = $2.split(','); @@ -348,11 +346,20 @@ export class GBVMService extends GBService { else { - return `${$1} = sys().get (${$2})`; + return `${$1} = sys().get (${$2}, headers)`; } - } + }); + code = code.replace(/\= NEW OBJECT/gi, ($0, $1, $2, $3) => { + return ` = {}`; + }); + + code = code.replace(/\= NEW ARRAY/gi, ($0, $1, $2, $3) => { + return ` = []`; + }); + + code = code.replace(/(go to)(\s)(.*)/gi, ($0, $1, $2, $3) => { return `gotoDialog(step, ${$3})\n`; }); @@ -401,6 +408,10 @@ export class GBVMService extends GBService { return `${$1} = sys().postByHttp (${$2}, ${$3}, headers)`; }); + code = code.replace(/(\w+)\s*\=\s*put\s*(.*),\s*(.*)/gi, ($0, $1, $2, $3) => { + return `${$1} = sys().putByHttp (${$2}, ${$3}, headers)`; + }); + code = code.replace(/(\w+)\s*\=\s*download\s*(.*),\s*(.*)/gi, ($0, $1, $2, $3) => { return `${$1} = sys().download (${$2}, ${$3})`; }); diff --git a/packages/basic.gblib/services/SystemKeywords.ts b/packages/basic.gblib/services/SystemKeywords.ts index 27740b4f..44a8949f 100644 --- a/packages/basic.gblib/services/SystemKeywords.ts +++ b/packages/basic.gblib/services/SystemKeywords.ts @@ -196,12 +196,12 @@ export class SystemKeywords { let isObject = false; if (Array.isArray(data)) { - isObject = Object.keys(data[0]) !== null; + isObject = Object.keys(data[1]) !== null; } if (isObject || JSON.parse(data) !== null) { - let keys = Object.keys(data[0]); + let keys = Object.keys(data[1]); if (headers) { @@ -286,7 +286,7 @@ export class SystemKeywords { // Guess fields from data variable into Tabulator fields collection. let fields = []; - let keys = Object.keys(data[1]); + let keys = Object.keys(data[0]); for (let i = 0; i < keys.length; i++) { fields.push({ field: keys[i], title: keys[i] }); } @@ -526,6 +526,12 @@ export class SystemKeywords { const botId = this.min.instance.botId; const path = `/${botId}.gbai/${botId}.gbdata`; + // Checks if it is a GB FILE object. + + if (data.data && data.filename) { + data = data.data; + } + try { await client .api(`${baseUrl}/drive/root:/${path}/${file}:/content`) @@ -587,27 +593,34 @@ export class SystemKeywords { * @example value = GET "file.xlsx", "A2" * */ - public async get(file: string, address: string): Promise { - GBLog.info(`BASIC: GET '${address}' in '${file}'.`); - let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min); - const botId = this.min.instance.botId; - const path = `/${botId}.gbai/${botId}.gbdata`; + public async get(file: string, addressOrHeaders: string, httpUsername, httpPs, qs, streaming): Promise { - let document = await this.internalGetDocument(client, baseUrl, path, file); + if (file.startsWith('http')) { - // Creates workbook session that will be discarded. + return await this.getByHttp(file, addressOrHeaders, httpUsername, httpPs, qs, streaming); + } + else { + GBLog.info(`BASIC: GET '${addressOrHeaders}' in '${file}'.`); + let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min); + const botId = this.min.instance.botId; + const path = `/${botId}.gbai/${botId}.gbdata`; - let sheets = await client - .api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`) - .get(); + let document = await this.internalGetDocument(client, baseUrl, path, file); - let results = await client - .api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')`) - .get(); + // Creates workbook session that will be discarded. - let val = results.text[0][0]; - GBLog.info(`BASIC: Getting '${file}' (GET). Value= ${val}.`); - return val; + 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='${addressOrHeaders}')`) + .get(); + + let val = results.text[0][0]; + GBLog.info(`BASIC: Getting '${file}' (GET). Value= ${val}.`); + return val; + } } public isValidDate(dt) { @@ -1356,11 +1369,10 @@ export class SystemKeywords { * */ public async getByHttp(url: string, headers: any, username: string, ps: string, qs: any, streaming = false) { - let options = { - encoding: "binary", - url: url, - headers: headers - }; + let options = { url: url }; + if (headers) { + options['headers'] = headers; + } if (username) { options['auth'] = { user: username, @@ -1387,6 +1399,28 @@ export class SystemKeywords { } } + /** + * Calls any REST API by using POST HTTP method. + * + * @example + * + * user = post "http://server/path", "data" + * talk "The updated user area is" + user.area + * + */ + public async putByHttp(url: string, data, headers) { + const options = { + uri: url, + json: true, + body: data, + headers: headers + }; + + let result = await request.put(options); + GBLog.info(`[PUT]: ${url} (${data}): ${result}`); + return typeof (result) === 'object' ? result : JSON.parse(result); + } + /** * Calls any REST API by using POST HTTP method. * diff --git a/packages/core.gbapp/services/GBMinService.ts b/packages/core.gbapp/services/GBMinService.ts index 0762ddd6..f4307a6d 100644 --- a/packages/core.gbapp/services/GBMinService.ts +++ b/packages/core.gbapp/services/GBMinService.ts @@ -255,6 +255,10 @@ export class GBMinService { if (!fs.existsSync(dir)) { mkdirp.sync(dir); } + dir = `work/${min.botId}.gbai/uploads`; + if (!fs.existsSync(dir)) { + mkdirp.sync(dir); + } // Loads Named Entity data for this bot.