Skip to content

Commit

Permalink
refactor: More consistent handling of QRS calls
Browse files Browse the repository at this point in the history
  • Loading branch information
mountaindude committed Nov 15, 2024
1 parent 939f49d commit c050445
Show file tree
Hide file tree
Showing 18 changed files with 146 additions and 483 deletions.
46 changes: 25 additions & 21 deletions src/lib/app/class_allapps.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ import * as rax from 'retry-axios';
import axios from 'axios';
import path from 'node:path';
import FormData from 'form-data';
import fs from "node:fs/promises";
import fs from 'node:fs/promises';
import fs2 from 'node:fs';
import { v4 as uuidv4, validate } from 'uuid';
import yesno from 'yesno';
import { logger, execPath, mergeDirFilePath, verifyFileExists, sleep, isPkg } from '../../globals.js';

import { logger, execPath, mergeDirFilePath, verifyFileExists, sleep } from '../../globals.js';
import { setupQrsConnection } from '../util/qseow/qrs.js';
import { getAppColumnPosFromHeaderRow } from '../util/qseow/lookups.js';
import QlikSenseApp from './class_app.js';
import { getTagIdByName } from '../util/qseow/tag.js';
import { getAppById, deleteAppById } from '../util/qseow/app.js';
import { getCustomPropertyDefinitionByName, doesCustomPropertyValueExist } from '../util/qseow/customproperties.js';
import { catchLog } from '../util/log.js';
import { getCertFilePaths } from '../util/qseow/cert.js';

class QlikSenseApps {
constructor() {
Expand All @@ -25,12 +27,14 @@ class QlikSenseApps {
this.appList = [];
this.options = options;

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
if (options.authType === 'cert') {
// Make sure certificates exist
this.fileCert = path.resolve(execPath, options.authCertFile);
this.fileCertKey = path.resolve(execPath, options.authCertKeyFile);
this.fileCertCA = path.resolve(execPath, options.authRootCertFile);
// Get certificate paths
const { fileCert, fileCertKey, fileCertCA } = getCertFilePaths(options);

this.fileCert = fileCert;
this.fileCertKey = fileCertKey;
this.fileCertCA = fileCertCA;
}

// Map that will connect app counter from Excel file with ID an app gets after import to QSEoW
Expand Down Expand Up @@ -117,7 +121,7 @@ class QlikSenseApps {
}
}

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfig;
if (this.options.authType === 'cert') {
if (filter === '') {
Expand Down Expand Up @@ -309,7 +313,7 @@ class QlikSenseApps {
.map((cp) => cp.trim());

if (tmpCustomProperty?.length === 2) {
const customProperty = await getCustomPropertyDefinitionByName('App', tmpCustomProperty[0], cpExisting);
const customProperty = getCustomPropertyDefinitionByName('App', tmpCustomProperty[0], cpExisting);
if (customProperty === false) {
// Failed getting custom property id, most likely because the custom property does not exist.
logger.error(
Expand All @@ -321,7 +325,7 @@ class QlikSenseApps {
}

// Verify custom property value is valid
const cpValueExists = await doesCustomPropertyValueExist(
const cpValueExists = doesCustomPropertyValueExist(
'App',
tmpCustomProperty[0],
tmpCustomProperty[1],
Expand Down Expand Up @@ -542,7 +546,7 @@ class QlikSenseApps {
// Function to update tags, custom properties and owner of uploaded app
async updateUploadedApp(newApp, uploadedAppId) {
try {
// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfigUploadedApp;
if (this.options.authType === 'cert') {
// Get info about just uploaded app
Expand Down Expand Up @@ -584,7 +588,7 @@ class QlikSenseApps {
`userDirectory eq '${newApp.appOwnerUserDirectory}' and userId eq '${newApp.appOwnerUserId}'`
);

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfigUser;
if (this.options.authType === 'cert') {
// Get info about just uploaded app
Expand Down Expand Up @@ -633,7 +637,7 @@ class QlikSenseApps {
// Pause for a while to let Sense repository catch up
await sleep(1000);

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfig2;
if (this.options.authType === 'cert') {
// Uppdate app with tags, custom properties and app owner
Expand Down Expand Up @@ -855,7 +859,7 @@ class QlikSenseApps {
{ name: 'name', value: appName },
];

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfig;
if (this.options.authType === 'cert') {
// Build QRS query
Expand Down Expand Up @@ -901,7 +905,7 @@ class QlikSenseApps {
// Define query parameters
const queryParameters = [{ name: 'app', value: targetAppId }];

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfig;
if (this.options.authType === 'cert') {
// Build QRS query
Expand Down Expand Up @@ -962,7 +966,7 @@ class QlikSenseApps {
filter = encodeURIComponent(`stream.name eq '${streamName}' and name eq '${appName}'`);
}

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfig;
if (this.options.authType === 'cert') {
// Build QRS query
Expand Down Expand Up @@ -1009,7 +1013,7 @@ class QlikSenseApps {
// Build QRS query
const filter = encodeURIComponent(`stream.name eq '${streamName}' and name eq '${appName}'`);

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfig;
if (this.options.authType === 'cert') {
// Build QRS query
Expand Down Expand Up @@ -1073,7 +1077,7 @@ class QlikSenseApps {
if (validate(uploadedAppInfo.appPublishToStream)) {
// It's a valid GUID

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
if (this.options.authType === 'cert') {
// Build QRS query
axiosConfigPublish = setupQrsConnection(this.options, {
Expand Down Expand Up @@ -1101,7 +1105,7 @@ class QlikSenseApps {
// Provided stream name is not a GUID, make sure only one stream exists with this name, then get its GUID
const filter = encodeURIComponent(`name eq '${uploadedAppInfo.appPublishToStream}'`);

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
if (this.options.authType === 'cert') {
// Build QRS query
axiosConfigPublish = setupQrsConnection(this.options, {
Expand Down Expand Up @@ -1266,7 +1270,7 @@ class QlikSenseApps {
const exportToken = uuidv4();
const excludeData = this.options.excludeAppData === 'true' ? 'true' : 'false';

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfig;
if (this.options.authType === 'cert') {
// Build QRS query
Expand Down Expand Up @@ -1379,7 +1383,7 @@ class QlikSenseApps {
} else {
writer = fs2.createWriteStream(fileName);

// Should cerrificates be used for authentication?
// Should certificates be used for authentication?
let axiosConfig;
if (this.options.authType === 'cert') {
// Build QRS query
Expand Down
3 changes: 0 additions & 3 deletions src/lib/cli/qseow-show-version.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { Option } from 'commander';

import { catchLog } from '../util/log.js';

export function setupQseowShowVersionCommand(qseow) {
qseow
.command('version')
.description('show version info')
.addOption(
new Option('--log-level <level>', 'log level').choices(['error', 'warn', 'info', 'verbose', 'debug', 'silly']).default('info')
)
// eslint-disable-next-line no-unused-vars
.action(async (options) => {
logger.verbose(`Version: ${appVersion}`);
});
Expand Down
3 changes: 1 addition & 2 deletions src/lib/cmd/qseow/importapp.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// import { csvParse } from 'csv-parse';

import xlsx from 'node-xlsx';

import { logger, setLoggingLevel, isPkg, execPath, verifyFileExists, isNumeric } from '../../../globals.js';
Expand All @@ -25,6 +23,7 @@ const importAppFromFile = async (options) => {

// Get all custom properties
const cpExisting = await getCustomPropertiesFromQseow(options);
logger.info(`Successfully retrieved ${cpExisting.length} custom properties from QSEoW`);

// Verify file exists
const appFileExists = await verifyFileExists(options.fileName);
Expand Down
6 changes: 1 addition & 5 deletions src/lib/cmd/qseow/importtask.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import xlsx from 'node-xlsx';
import { parse } from 'csv-parse';
import fs from 'node:fs';
import { finished } from 'node:stream/promises';

import { logger, setLoggingLevel, isPkg, execPath, verifyFileExists, isNumeric } from '../../../globals.js';
import QlikSenseTasks from '../../task/class_alltasks.js';
Expand All @@ -22,7 +21,6 @@ const getHeaders = async (options) => {
);

// Get the header row
// eslint-disable-next-line no-restricted-syntax
for await (const record of parser) {
if (record.info.lines === 1) {
// Header row
Expand All @@ -39,7 +37,6 @@ const processCsvFile = async (options) => {
const headerRow = [];

// Push all column headers to array
// eslint-disable-next-line no-restricted-syntax
for (const record of headers[0]) {
// Get each column header text
headerRow.push(record);
Expand Down Expand Up @@ -284,7 +281,6 @@ const processCsvFile = async (options) => {
})
);

// eslint-disable-next-line no-restricted-syntax
for await (const record of parser) {
// ALways add the header line
if (record.info.lines === 1) {
Expand Down Expand Up @@ -319,6 +315,7 @@ const importTaskFromFile = async (options) => {

// Get all custom properties
const cpExisting = await getCustomPropertiesFromQseow(options);
logger.info(`Successfully retrieved ${cpExisting.length} custom properties from QSEoW`);

// Verify task definitions file exists
const taskFileExists = await verifyFileExists(options.fileName);
Expand All @@ -343,7 +340,6 @@ const importTaskFromFile = async (options) => {
data: [],
};

// eslint-disable-next-line no-restricted-syntax
for (const item of tmpTasksFromFile) {
tasksFromFile.data.push(item);
}
Expand Down
18 changes: 1 addition & 17 deletions src/lib/cmd/qseow/settaskcp.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ const updateTask = async (options, customPropertyDef, task) =>

// Should new values be replacing or appended to existing values?
if (options.updateMode === 'append') {
// eslint-disable-next-line no-restricted-syntax
for (const newCpValue of options.customPropertyValue) {
// Don't append a value if it's already set for the custom property
if (!newPayload.task?.customProperties?.find((item) => item.value === newCpValue))
Expand All @@ -52,14 +51,13 @@ const updateTask = async (options, customPropertyDef, task) =>
});
}
} else if (options.updateMode === 'replace') {
// First clear the custom property, then add the values provided via --custom-property-value
// First copy all existing CP values that should not be replaced to the new payload
const cp = newPayload.task?.customProperties.filter(
(existingCustomProperty) => existingCustomProperty.definition.name !== options.customPropertyName
);
newPayload.task.customProperties = cp;

// Now add the new CP values
// eslint-disable-next-line no-restricted-syntax
for (const newCpValue of options.customPropertyValue) {
newPayload.task?.customProperties?.push({
definition: { id: customPropertyDef[0].id, name: customPropertyDef[0].name },
Expand All @@ -75,12 +73,10 @@ const updateTask = async (options, customPropertyDef, task) =>
let ok;
logger.info();
if (options.updateMode === 'replace') {
// eslint-disable-next-line no-await-in-loop
ok = await yesno({
question: ` Replace current values in custom property "${options.customPropertyName}" with new ones? (y/n)`,
});
} else if (options.updateMode === 'append') {
// eslint-disable-next-line no-await-in-loop
ok = await yesno({
question: ` Append new values to custom property "${options.customPropertyName}"? (y/n)`,
});
Expand All @@ -92,7 +88,6 @@ const updateTask = async (options, customPropertyDef, task) =>
logger.debug(`SET RELOAD TASK CP: Update payload for task ${task.id}: ${JSON.stringify(newPayload, null, 2)}`);

if (options.dryRun === undefined || options.dryRun === false) {
// eslint-disable-next-line no-await-in-loop
updateResult = await updateReloadTask(options, newPayload);
} else {
logger.info(`DRY RUN: Update of task custom property ${task.customPropertyName} would happen here.`);
Expand All @@ -101,7 +96,6 @@ const updateTask = async (options, customPropertyDef, task) =>
logger.info(`Did not update task "${task.name}"`);
}
} else if (options.dryRun === undefined || options.dryRun === false) {
// eslint-disable-next-line no-await-in-loop
updateResult = await updateReloadTask(options, newPayload);
} else {
logger.info(`DRY RUN: Update of task custom property ${task.customPropertyName} would happen here.`);
Expand All @@ -123,7 +117,6 @@ const updateTask = async (options, customPropertyDef, task) =>
// Custom property does NOT already have the custom property set for this task.

// Add CP values to task
// eslint-disable-next-line no-restricted-syntax
for (const newCpValue of options.customPropertyValue) {
newPayload.task?.customProperties?.push({
definition: { id: customPropertyDef[0].id, name: customPropertyDef[0].name },
Expand All @@ -133,7 +126,6 @@ const updateTask = async (options, customPropertyDef, task) =>

// Update task
logger.debug(`SET RELOAD TASK CP: Update payload for task ${task.id}: ${JSON.stringify(newPayload, null, 2)}`);
// eslint-disable-next-line no-await-in-loop
const updateResult = await updateReloadTask(options, newPayload);

if (updateResult) {
Expand Down Expand Up @@ -177,7 +169,6 @@ const setTaskCustomProperty = async (options) => {
}

// Ensure that the new CP values are among the CP's choiceValues
// eslint-disable-next-line no-restricted-syntax
for (const newCPValue of options.customPropertyValue) {
if (!customPropertyDef[0].choiceValues.find((item) => item === newCPValue)) {
// An invalud custom property value detected
Expand All @@ -195,22 +186,15 @@ const setTaskCustomProperty = async (options) => {
// Log which tasks will be processed
logger.info(`Number of tasks that will be updated: ${taskList.length}`);

// const updateTasks = [];
// eslint-disable-next-line no-restricted-syntax
for (const task of taskList) {
// updateTasks.push(updateTask(options, customPropertyDef, task));

logger.info(``);
logger.info(`-----------------------------------------------------------`);
logger.info(`Processing task "${task.name}" with ID=${task.id}`);

// eslint-disable-next-line no-await-in-loop
const res = await updateTask(options, customPropertyDef, task);
logger.debug(`Custom property update result: ${res}`);
}

// await Promise.all(updateTasks);
// logger.debug('Update task custom property: All promises resolved');
return true;
}
} catch (err) {
Expand Down
14 changes: 9 additions & 5 deletions src/lib/task/class_allcompositeevents.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import axios from 'axios';
import path from 'node:path';

import { logger, execPath, verifyFileExists } from '../../globals.js';
import { setupQrsConnection } from '../util/qseow/qrs.js';
import QlikSenseCompositeEvent from './class_compositeevent.js';
import { catchLog } from '../util/log.js';
import { getCertFilePaths } from '../util/qseow/cert.js';

class QlikSenseCompositeEvents {
// eslint-disable-next-line no-useless-constructor
constructor() {
//
}
Expand All @@ -16,11 +17,14 @@ class QlikSenseCompositeEvents {
this.compositeEventList = [];
this.options = options;

// Should certificates be used for authentication?
if (this.options.authType === 'cert') {
// Make sure certificates exist
this.fileCert = path.resolve(execPath, options.authCertFile);
this.fileCertKey = path.resolve(execPath, options.authCertKeyFile);
this.fileCertCA = path.resolve(execPath, options.authRootCertFile);
// Get certificate paths
const { fileCert, fileCertKey, fileCertCA } = getCertFilePaths(options);

this.fileCert = fileCert;
this.fileCertKey = fileCertKey;
this.fileCertCA = fileCertCA;
}
} catch (err) {
catchLog(`GET COMPOSITE EVENT`, err);
Expand Down
Loading

0 comments on commit c050445

Please sign in to comment.