diff --git a/package.json b/package.json index 7e42f4a9..61ab5bc6 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "botlib": "3.0.11", "c3-chart-maker": "0.2.8", "cd": "0.3.3", - "chatgpt": "^2.4.2", + "chatgpt": "2.4.2", "chrome-remote-interface": "0.31.3", "cli-progress": "3.11.2", "cli-spinner": "0.2.10", diff --git a/packages/basic.gblib/services/GBVMService.ts b/packages/basic.gblib/services/GBVMService.ts index 3abfd825..02a49774 100644 --- a/packages/basic.gblib/services/GBVMService.ts +++ b/packages/basic.gblib/services/GBVMService.ts @@ -373,6 +373,7 @@ export class GBVMService extends GBService { // Imports npm packages for this .gbdialog conversational application. require('isomorphic-fetch'); + const http = require('node:http'); const createRpcClient = require("@push-rpc/core").createRpcClient; const createHttpClient = require("@push-rpc/http").createHttpClient; @@ -454,15 +455,16 @@ export class GBVMService extends GBService { const optsRPC = {callTimeout: this.callTimeout}; let url; + const agent = http.Agent({ keepAlive: true }); url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/dk'; - const dk = (await createRpcClient(0, () => createHttpClient(url), optsRPC)).remote; + const dk = (await createRpcClient(0, () => createHttpClient(url, {agent: agent}), optsRPC)).remote; url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/sys'; - const sys = (await createRpcClient(0, () => createHttpClient(url), optsRPC)).remote; + const sys = (await createRpcClient(0, () => createHttpClient(url, {agent: agent}), optsRPC)).remote; url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/wa'; - const wa = (await createRpcClient(0, () => createHttpClient(url), optsRPC)).remote; + const wa = (await createRpcClient(0, () => createHttpClient(url, {agent: agent}), optsRPC)).remote; url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/img'; - const img = (await createRpcClient(0, () => createHttpClient(url), optsRPC)).remote; + const img = (await createRpcClient(0, () => createHttpClient(url, {agent: agent}), optsRPC)).remote; ${code} diff --git a/packages/basic.gblib/services/KeywordsExpressions.ts b/packages/basic.gblib/services/KeywordsExpressions.ts index 11866007..6f921723 100644 --- a/packages/basic.gblib/services/KeywordsExpressions.ts +++ b/packages/basic.gblib/services/KeywordsExpressions.ts @@ -351,11 +351,11 @@ export class KeywordsExpressions { __url = __data.links?.next?.uri; __seekToken = __data.links?.self?.headers["MS-ContinuationToken"] - __totalCount = __data["totalCount"]; + __totalCount = __data["totalCount"] ? __data["totalCount"] : __data.length; while (__next) { - let ${$1} = __data.items[__index]; + let ${$1} = __data?.items ? __data?.items[__index] : __data[__index]; `; } ]; @@ -370,21 +370,21 @@ export class KeywordsExpressions { if (__index >= __totalCount) { - // Check if HTTP call limit has reached. + // Checks if HTTP call limit has reached. if (__calls < __totalCalls) { - // Perform GET request using the constructed URL + // Performs GET request using the constructed URL __data = await sys.get ({pid: pid, file: __url, addressOrHeaders: headers, httpUsername, httpPs}); - // Update current variable handlers. + // Updates current variable handlers. __url = __data.links?.next?.uri; __seekToken = __data.links?.self?.headers["MS-ContinuationToken"] __totalCount = __data["totalCount"]; - index = 0; + __index = 0; __calls++; } else { @@ -392,9 +392,8 @@ export class KeywordsExpressions { next = false; } - - index = index + 1; } + __index = __index + 1; }`; } ]; diff --git a/packages/basic.gblib/services/SystemKeywords.ts b/packages/basic.gblib/services/SystemKeywords.ts index 89c6f3f4..f0f8c2d7 100644 --- a/packages/basic.gblib/services/SystemKeywords.ts +++ b/packages/basic.gblib/services/SystemKeywords.ts @@ -656,27 +656,31 @@ export class SystemKeywords { */ public async saveToStorage({ pid, table, fieldsValues, fieldsNames }): Promise { - GBLog.info(`BASIC: Saving '${table}' (SAVE). Values: ${fieldsValues.join(',')}.`); + GBLog.info(`BASIC: Saving to storage '${table}' (SAVE).`); const minBoot = GBServer.globals.minBoot as any; const definition = minBoot.core.sequelize.models[table]; - let data = {}; - let index = 0; + let out = []; + let data = {}, data2 = {}; - data = this.flattenJSON(fieldsValues,{}, '') + // Flattern JSON to a table. - fieldsNames.forEach(field => { - field = field.charAt(0).toUpperCase() + field.slice(1); - data[field] = fieldsValues[index++]; + data = this.flattenJSON(fieldsValues, {}, '') + + // Uppercases fields. + + Object.keys(data).forEach(field => { + const field2 = field.charAt(0).toUpperCase() + field.slice(1); + data2[field2] = data[field]; }); - return await definition.create(data); + return await definition.create(data2); } /** * Saves the content of several variables to a new row in a tabular file. * - * @exaple SAVE "customers.xlsx", name, email, phone, address, city, state, country + * @example SAVE "customers.xlsx", name, email, phone, address, city, state, country * */ public async save({ pid, file, args }): Promise { @@ -1506,12 +1510,12 @@ export class SystemKeywords { return GBAdminService.getRndPassword(); } - private flattenJSON(obj, res, extraKey, hierarchy=false) { + private flattenJSON(obj, res, extraKey, hierarchy = false) { for (let key in obj) { if (typeof obj[key] !== 'object') { res[extraKey + key] = obj[key]; } else { - this.flattenJSON(obj[key], res, hierarchy?`${extraKey}${key}.`:''); + this.flattenJSON(obj[key], res, hierarchy ? `${extraKey}${key}.` : ''); }; }; return res; @@ -1555,246 +1559,6 @@ export class SystemKeywords { options['qs'] = qs; } - - let r1 = { - "totalCount": 2, - "items": [ - { - "partnerId": "00083575-bbd0-54de-b2ad-0f5b0e927d71", - "partnerName": "MTBC", - "customerId": "", - "customerName": "", - "customerDomainName": "", - "invoiceNumber": "", - "productId": "", - "skuId": "", - "availabilityId": "", - "skuName": "VM-Series Next-Generation Firewall (Bundle 2 PAYG)", - "productName": "VM-Series Next Generation Firewall", - "publisherName": "Test Alto Networks, Inc.", - "publisherId": "", - "subscriptionId": "12345678-04d9-421c-baf8-e3b8dd62ddba", - "subscriptionDescription": "Pay-As-You-Go", - "chargeStartDate": "2019-01-01T00:00:00Z", - "chargeEndDate": "2019-02-01T00:00:00Z", - "usageDate": "2019-01-01T00:00:00Z", - "meterType": "1 Compute Hour - 4core", - "meterCategory": "Virtual Machine Licenses", - "meterId": "4core", - "meterSubCategory": "VM-Series Next Generation Firewall", - "meterName": "VM-Series Next Generation Firewall - VM-Series Next-Generation Firewall (Bundle 2 PAYG) - 4 Core Hours", - "meterRegion": "", - "unitOfMeasure": "1 Hour", - "resourceLocation": "EASTUS", - "consumedService": "Microsoft.Compute", - "resourceGroup": "ECH-PAN-RG", - "resourceUri": "/subscriptions/12345678-04d9-421c-baf8-e3b8dd62ddba/resourceGroups/ECH-PAN-RG/providers/Microsoft.Compute/virtualMachines/echpanfw", - "tags": "", - "additionalInfo": "{ \"ImageType\": null, \"ServiceType\": \"Standard_D3_v2\", \"VMName\": null, \"VMProperties\": null, \"UsageType\": \"ComputeHR_SW\"}", - "serviceInfo1": "", - "serviceInfo2": "", - "customerCountry": "", - "mpnId": "1234567", - "resellerMpnId": "", - "chargeType": "", - "unitPrice": 1.2799888920023, - "quantity": 24.0, - "unitType": "", - "billingPreTaxTotal": 30.7197334080551, - "billingCurrency": "USD", - "pricingPreTaxTotal": 30.7197334080551, - "pricingCurrency": "USD", - "entitlementId": "3f47bcf1-965d-40a1-a2bc-3d5db3653250", - "entitlementDescription": "Partner Subscription", - "pcToBCExchangeRate": 1, - "pcToBCExchangeRateDate": "2019-08-01T00:00:00Z", - "effectiveUnitPrice": 0, - "rateOfPartnerEarnedCredit": 0, - "rateOfCredit": 0, - "creditType": "Credit Not Applied", - "invoiceLineItemType": "usage_line_items", - "billingProvider": "marketplace", - "benefitOrderId": "5ea053d6-4a0d-46ef-bc82-15065b475d01", - "benefitId": "28ddab06-2c5b-479e-88bb-7b7bfda4e7fd", - "benefitType": "SavingsPlan", - "attributes": { - "objectType": "DailyRatedUsageLineItem" - } - }, - { - "partnerId": "00083575-bbd0-54de-b2ad-0f5b0e927d71", - "partnerName": "MTBC", - "customerId": "", - "customerName": "", - "customerDomainName": "", - "invoiceNumber": "", - "productId": "", - "skuId": "", - "availabilityId": "", - "skuName": "VM-Series Next-Generation Firewall (Bundle 2 PAYG)", - "productName": "VM-Series Next Generation Firewall", - "publisherName": "Test Alto Networks, Inc.", - "publisherId": "", - "subscriptionId": "12345678-04d9-421c-baf8-e3b8dd62ddba", - "subscriptionDescription": "Pay-As-You-Go", - "chargeStartDate": "2019-01-01T00:00:00Z", - "chargeEndDate": "2019-02-01T00:00:00Z", - "usageDate": "2019-01-02T00:00:00Z", - "meterType": "1 Compute Hour - 4core", - "meterCategory": "Virtual Machine Licenses", - "meterId": "4core", - "meterSubCategory": "VM-Series Next Generation Firewall", - "meterName": "VM-Series Next Generation Firewall - VM-Series Next-Generation Firewall (Bundle 2 PAYG) - 4 Core Hours", - "meterRegion": "", - "unitOfMeasure": "1 Hour", - "resourceLocation": "EASTUS", - "consumedService": "Microsoft.Compute", - "resourceGroup": "ECH-PAN-RG", - "resourceUri": "/subscriptions/12345678-04d9-421c-baf8-e3b8dd62ddba/resourceGroups/ECH-PAN-RG/providers/Microsoft.Compute/virtualMachines/echpanfw", - "tags": "", - "additionalInfo": "{ \"ImageType\": null, \"ServiceType\": \"Standard_D3_v2\", \"VMName\": null, \"VMProperties\": null, \"UsageType\": \"ComputeHR_SW\"}", - "serviceInfo1": "", - "serviceInfo2": "", - "customerCountry": "", - "mpnId": "1234567", - "resellerMpnId": "", - "chargeType": "", - "unitPrice": 1.2799888920023, - "quantity": 24.0, - "unitType": "", - "billingPreTaxTotal": 30.7197334080551, - "billingCurrency": "USD", - "pricingPreTaxTotal": 30.7197334080551, - "pricingCurrency": "USD", - "entitlementId": "31cdf47f-b249-4edd-9319-637862d12345", - "entitlementDescription": "Partner Subscription", - "pcToBCExchangeRate": 1, - "pcToBCExchangeRateDate": "2019-08-01T00:00:00Z", - "effectiveUnitPrice": 0, - "rateOfPartnerEarnedCredit": 0, - "rateOfCredit": 1, - "creditType": "Azure Credit Applied", - "invoiceLineItemTypce": "usage_line_items", - "billingProvider": "marketplace", - "benefitOrderId": "", - "benefitId": "", - "benefitType": "Charge", - "attributes": { - "objectType": "DailyRatedUsageLineItem" - } - } - ], - "links": { - "self": { - "uri": "/invoices/unbilled/lineitems?provider=onetime&invoicelineitemtype=usagelineitems¤cycode=usd&period=previous&size=2000", - "method": "GET", - "headers": [] - }, - "next": { - "uri": "/invoices/unbilled/lineitems?provider=onetime&invoicelineitemtype=usagelineitems¤cycode=usd&period=previous&size=2000&seekOperation=Next", - "method": "GET", - "headers": [ - { - "key": "MS-ContinuationToken", - "value": "AQAAAA==" - } - ] - } - }, - "attributes": { - "objectType": "Collection" - } - }; - - let r2 = - { - "totalCount": 1, - "items": [ - { - "partnerId": "00083575-bbd0-54de-b2ad-0f5b0e927d71", - "partnerName": "MTBC", - "customerId": "", - "customerName": "", - "customerDomainName": "", - "invoiceNumber": "", - "productId": "", - "skuId": "", - "availabilityId": "", - "skuName": "VM-Series Next-Generation Firewall (Bundle 2 PAYG)", - "productName": "VM-Series Next Generation Firewall", - "publisherName": "Test Alto Networks, Inc.", - "publisherId": "", - "subscriptionId": "12345678-04d9-421c-baf8-e3b8dd62ddba", - "subscriptionDescription": "Pay-As-You-Go", - "chargeStartDate": "2019-01-01T00:00:00Z", - "chargeEndDate": "2019-02-01T00:00:00Z", - "usageDate": "2019-01-02T00:00:00Z", - "meterType": "1 Compute Hour - 4core", - "meterCategory": "Virtual Machine Licenses", - "meterId": "4core", - "meterSubCategory": "VM-Series Next Generation Firewall", - "meterName": "VM-Series Next Generation Firewall - VM-Series Next-Generation Firewall (Bundle 2 PAYG) - 4 Core Hours", - "meterRegion": "", - "unitOfMeasure": "1 Hour", - "resourceLocation": "EASTUS", - "consumedService": "Microsoft.Compute", - "resourceGroup": "ECH-PAN-RG", - "resourceUri": "/subscriptions/12345678-04d9-421c-baf8-e3b8dd62ddba/resourceGroups/ECH-PAN-RG/providers/Microsoft.Compute/virtualMachines/echpanfw", - "tags": "", - "additionalInfo": "{ \"ImageType\": null, \"ServiceType\": \"Standard_D3_v2\", \"VMName\": null, \"VMProperties\": null, \"UsageType\": \"ComputeHR_SW\"}", - "serviceInfo1": "", - "serviceInfo2": "", - "customerCountry": "", - "mpnId": "1234567", - "resellerMpnId": "", - "chargeType": "", - "unitPrice": 1.2799888920023, - "quantity": 24.0, - "unitType": "", - "billingPreTaxTotal": 30.7197334080551, - "billingCurrency": "USD", - "pricingPreTaxTotal": 30.7197334080551, - "pricingCurrency": "USD", - "entitlementId": "31cdf47f-b249-4edd-9319-637862d8c0b4", - "entitlementDescription": "Partner Subscription", - "pcToBCExchangeRate": 1, - "pcToBCExchangeRateDate": "2019-08-01T00:00:00Z", - "effectiveUnitPrice": 0, - "rateOfPartnerEarnedCredit": 0.15, - "rateOfCredit": 0.15, - "creditType": "Partner Earned Credit Applied", - "invoiceLineItemType": "usage_line_items", - "billingProvider": "marketplace", - "benefitOrderId": "", - "benefitId": "", - "benefitType": "Charge", - "attributes": { - "objectType": "DailyRatedUsageLineItem" - } - } - ], - "links": { - "self": { - "uri": "/invoices/unbilled/lineitems?provider=onetime&invoicelineitemtype=usagelineitems¤cycode=usd&period=previous&size=2000", - "method": "GET", - "headers": [] - } - }, - "attributes": { - "objectType": "Collection" - } - }; - - - // let result; - // if (!SystemKeywords.aa) { - // SystemKeywords.aa = 1; - // return r1; - // } else { - // SystemKeywords.aa = null; - // return r2; - // } - const result = await fetch(url, options); if (result.status === 2000) { @@ -2126,7 +1890,9 @@ export class SystemKeywords { throw new Error(`TABLE ${file} not found. Check TABLE keywords.`); } rows = await t.findAll({}); - header = rows['dataNames']; + if (rows.length > 0) { + header = Object.keys(rows[0].dataValues) + } } else { const botId = min.instance.botId; @@ -2151,18 +1917,15 @@ export class SystemKeywords { rows = results.text; } - // As BASIC uses arrays starting with 1 (one) as index, - // a ghost element is added at 0 (zero) position. - let table = []; - table.push({ gbarray: '0' }); - let foundIndex = 1; + let foundIndex = 0; // Fills the row variable. for (; foundIndex < rows.length; foundIndex++) { let row = {}; const xlRow = rows[foundIndex]; + row = xlRow.dataValues ? xlRow.dataValues : xlRow; for (let colIndex = 0; colIndex < xlRow.length; colIndex++) { const propertyName = header[colIndex]; let value = xlRow[colIndex]; @@ -2196,11 +1959,14 @@ export class SystemKeywords { // Scans all sheet lines and compare keys. - const row = data[i]; + let row = data[i]; let found; let key1Value; if (key1Index) { + + key1 = key1.charAt(0).toLowerCase() + key1.slice(1); + key1Value = row[key1]; const foundRow = key1Index[key1Value]; if (foundRow) { @@ -2209,22 +1975,27 @@ export class SystemKeywords { } if (found) { + + row = this.flattenJSON(row, {}, '') + let keys = Object.keys(row); - for (let j = 0; j < keys.length; j++) { + for (let j = 0; j < header.length; j++) { + const columnName = header[j]; - const value = row[keys[j]]; + const columnNameLower = columnName.charAt(0).toLowerCase() + columnName.slice(1); + const value = row[columnNameLower]; - if (storage) { + if (value !== found[columnName]) { - const obj = { id: keys[j], columnName: value }; - await t.update(obj, { where: { key1: key1Value } }); + if (storage) { - } else { + const obj = { columnName: value }; + await t.update(obj, { where: { key1: key1Value } }); - const cell = `${this.numberToLetters(j)}${i + 1}`; - const address = `${cell}:${cell}`; + } else { - if (value !== found[columnName]) { + const cell = `${this.numberToLetters(j)}${i + 1}`; + const address = `${cell}:${cell}`; await this.set({ pid, handle: null, file, address, value }); merges++; @@ -2233,10 +2004,27 @@ export class SystemKeywords { } } else { + + // Check if is a tree or flat object. + + const hasSubObject = (products) => { + for (var key in products) { + if (!products.hasOwnProperty(key)) continue; + if (typeof products[key] === "object") return true; + } + return false; + } + let fieldsValues = []; - let fieldsNames = Object.keys(row); - for (let j = 0; j < fieldsNames.length; j++) { - fieldsValues.push(row[fieldsNames[j]]); + const fieldsNames = Object.keys(row); + + if (hasSubObject(row)) { + fieldsValues = row; + } + else { + for (let j = 0; j < fieldsNames.length; j++) { + fieldsValues.push(row[fieldsNames[j]]); + } } if (storage) { @@ -2250,7 +2038,7 @@ export class SystemKeywords { } } - if (table.length === 1) { + if (table.length === 0) { GBLog.info(`BASIC: MERGE ran but updated zero rows.`); return null; } else {