UNPKG

@tduniec/backstage-plugin-time-saver-backend

Version:

This plugin provides an implementation of charts and statistics related to your time savings that are coming from usage of your templates. Plugins is built from frontend and backend part. Backend plugin is responsible for scheduled stats parsing process a

410 lines (406 loc) 13 kB
'use strict'; var scaffolderClient = require('./scaffolderClient.cjs.js'); var defaultValues = require('./defaultValues.cjs.js'); class TimeSaverApi { constructor(logger, config, auth, timeSaverDb, scaffolderDb) { this.logger = logger; this.config = config; this.auth = auth; this.timeSaverDb = timeSaverDb; this.scaffolderDb = scaffolderDb; } async getStatsByTemplateTaskId(templateTaskId, query) { const templateName = await this.timeSaverDb.getTemplateNameByTsId( templateTaskId, query ); const queryResult = await this.timeSaverDb.getStatsByTemplateTaskId( templateTaskId, query ); const outputBody = { templateTaskId, templateName, stats: queryResult }; this.logger.debug(JSON.stringify(outputBody)); return outputBody; } async getStatsByTeam(team, query) { const queryResult = await this.timeSaverDb.getStatsByTeam(team, query); const outputBody = { team, stats: queryResult || [] }; this.logger.debug(JSON.stringify(outputBody)); return outputBody; } async getStatsByTemplate(template, query) { const queryResult = await this.timeSaverDb.getStatsByTemplate( template, query ); const outputBody = { template_name: template, stats: queryResult || [] }; this.logger.debug(JSON.stringify(outputBody)); return outputBody; } async getAllStats(query) { const queryResult = await this.timeSaverDb.getAllStats(query); const outputBody = { stats: queryResult || [] }; this.logger.debug(JSON.stringify(outputBody)); return outputBody; } async getGroupDivisionStats(query) { const queryResult = await this.timeSaverDb.getGroupSavingsDivision(query); const outputBody = { stats: queryResult || [] }; this.logger.debug(JSON.stringify(outputBody)); return outputBody; } async getDailyTimeSummariesTeamWise(query) { const queryResult = await this.timeSaverDb.getDailyTimeSummariesTeamWise( query ); const outputBody = { stats: queryResult || [] }; this.logger.debug(JSON.stringify(outputBody)); return outputBody; } async getDailyTimeSummariesTemplateWise(query) { const queryResult = await this.timeSaverDb.getDailyTimeSummariesTemplateWise(query); const outputBody = { stats: queryResult || [] }; this.logger.debug(JSON.stringify(outputBody)); return outputBody; } async getTimeSummarySavedTeamWise(query) { const queryResult = await this.timeSaverDb.getTimeSummarySavedTeamWise( query ); const outputBody = { stats: queryResult || [] }; this.logger.debug(JSON.stringify(outputBody)); return outputBody; } async getTimeSummarySavedTemplateWise(query) { const queryResult = await this.timeSaverDb.getTimeSummarySavedTemplateWise( query ); const outputBody = { stats: queryResult || [] }; this.logger.debug(JSON.stringify(outputBody)); return outputBody; } async getSampleMigrationClassificationConfig(customClassificationRequest, options) { if (typeof customClassificationRequest === "object" && !Object.keys(customClassificationRequest).length) { const errorMessage = `getSampleMigrationClassificationConfig : customClassificationRequest cannot be an empty object`; this.logger.error( `getSampleMigrationClassificationConfig : customClassificationRequest cannot be an empty object` ); return { status: "FAIL", errorMessage }; } const sampleClassification = customClassificationRequest || defaultValues.DEFAULT_SAMPLE_CLASSIFICATION; const templatesList = options?.useScaffolderTasksEntries ? (await this.getAllTemplateTasks()).templateTasks : defaultValues.DEFAULT_SAMPLE_TEMPLATES_TASKS; this.logger.debug( `Generating sample classification configuration with ${options?.useScaffolderTasksEntries ? "scaffolder DB" : "user-defined"} templates tasks list and ${customClassificationRequest ? "user-defined" : "default"} classification` ); return { status: "OK", data: templatesList.map((t) => ({ entityRef: t, ...sampleClassification })) }; } async getAllGroups(query) { let groups; let outputBody = { groups: [], errorMessage: "" }; const queryResult = await this.timeSaverDb.getDistinctColumn("team", query); if (queryResult && queryResult.team.length > 0) { groups = queryResult.team.map((e) => e.toString()); outputBody = { ...outputBody, groups }; this.logger.debug(JSON.stringify(outputBody)); } else { const errorMessage = "getAllGroups - DB returned 0 rows"; outputBody = { ...outputBody, errorMessage }; this.logger.warn(errorMessage); } return outputBody; } async getAllTemplateNames(query) { let templates; let outputBody = { templates: [], errorMessage: "" }; const queryResult = await this.timeSaverDb.getDistinctColumn( "template_name", query ); if (queryResult && queryResult.template_name.length > 0) { templates = queryResult.template_name.map((e) => e.toString()); outputBody = { ...outputBody, templates }; this.logger.debug(JSON.stringify(outputBody)); } else { const errorMessage = "getAllGroups - DB returned 0 rows"; outputBody = { ...outputBody, errorMessage }; this.logger.warn(errorMessage); } return outputBody; } async getAllTemplateTasks() { let templateTasks; let outputBody = { templateTasks: [], errorMessage: "" }; const queryResult = await this.timeSaverDb.getDistinctColumn( "template_task_id", {} ); if (queryResult && queryResult.template_task_id.length > 0) { templateTasks = queryResult.template_task_id.map((e) => e.toString()); outputBody = { ...outputBody, templateTasks }; this.logger.debug(JSON.stringify(outputBody)); } else { const errorMessage = "getAllGroups - DB returned 0 rows"; outputBody = { ...outputBody, errorMessage }; this.logger.warn(errorMessage); } return outputBody; } async getTemplateCount(query) { let outputBody = { templateCount: 0, errorMessage: "" }; const queryResult = await this.timeSaverDb.getTemplateCount(query); if (typeof queryResult === "number") { outputBody = { templateCount: queryResult }; this.logger.debug(`getTemplateCount: ${JSON.stringify(outputBody)}`); } else { const errorMessage = "getTemplateCount did not return any results"; outputBody = { ...outputBody, errorMessage }; this.logger.warn(errorMessage); } return outputBody; } async getTimeSavedSum(divider, query) { let outputBody = { timeSaved: 0, errorMessage: "" }; const dividerInt = divider ?? 1; const queryResult = await this.timeSaverDb.getTimeSavedSum(query); if (typeof queryResult === "number") { outputBody = { timeSaved: queryResult ? queryResult / dividerInt : queryResult }; this.logger.debug(JSON.stringify(outputBody)); } else { const errorMessage = "getTimeSavedSum - DB returned 0 rows"; outputBody = { ...outputBody, errorMessage }; this.logger.warn(errorMessage); } return outputBody; } async updateTemplatesWithSubstituteData(requestData) { let templateClassification; let migrationStatisticsReport = { updatedTemplates: { total: 0, list: [] }, missingTemplates: { total: 0, list: [] } }; if (requestData) { try { if (typeof requestData !== "object") { templateClassification = JSON.parse(requestData); } else { templateClassification = requestData; } if (!templateClassification || !Object.keys(templateClassification).length) { throw new Error( `Invalid classification ${JSON.stringify( requestData )}. Either it was empty or could not parse JSON string. Aborting...` ); } this.logger.debug( `Found classification in API POST body: ${JSON.stringify( templateClassification )}` ); } catch (error) { const msg = `Migration: Could not parse JSON object from POST call body "${JSON.stringify( requestData )}", aborting...`; this.logger.error(msg, error ? error : void 0); return { status: "FAIL", message: `${msg} - ${error}` }; } } else { const tsConfigObj = this.config.getOptionalString("ts.backward.config") || void 0; if (!tsConfigObj) { const errorMessage = "Migration: Could not find backward migration configuration in app-config.x.yaml, aborting..."; this.logger.error(errorMessage); return { status: "FAIL", message: errorMessage }; } try { templateClassification = JSON.parse(String(tsConfigObj)); this.logger.debug( `Found classification in app-config.x.yaml: ${JSON.stringify( templateClassification )}` ); } catch (error) { const msg = "Migration: Could not parse backward migration configuration as JSON object from app-config.x.yaml, aborting..."; this.logger.error(msg, error ? error : void 0); return { status: "FAIL", message: `${msg} - ${error}` }; } } try { this.logger.info(`Starting backward migration`); const taskTemplateList = await new scaffolderClient.ScaffolderClient( this.logger, this.config, this.auth ).fetchTemplatesFromScaffolder(); for (let i = 0; i < taskTemplateList.length; i++) { const scaffolderTaskRecord = taskTemplateList[i]; this.logger.debug( `Migrating template ${JSON.stringify(scaffolderTaskRecord)}` ); const { entityRef: templateEntityRef } = scaffolderTaskRecord.spec.templateInfo; this.logger.debug( `Found template with entityRef: ${templateEntityRef}` ); const classificationEntry = templateClassification.find( (con) => con.entityRef === templateEntityRef ); if (classificationEntry) { const newClassificationEntry = Object.assign( {}, classificationEntry ); delete newClassificationEntry.entityRef; const newTemplateTaskRecordSpecs = { ...scaffolderTaskRecord.spec, templateInfo: { ...scaffolderTaskRecord.spec.templateInfo, entity: { ...scaffolderTaskRecord.spec.templateInfo.entity, metadata: { ...scaffolderTaskRecord.spec.templateInfo.entity.metadata, substitute: newClassificationEntry } } } }; const patchQueryResult = await this.scaffolderDb.updateTemplateTaskById( scaffolderTaskRecord.id, JSON.stringify(newTemplateTaskRecordSpecs) ); if (patchQueryResult) { migrationStatisticsReport = { ...migrationStatisticsReport, updatedTemplates: { total: ++migrationStatisticsReport.updatedTemplates.total, list: [ ...migrationStatisticsReport.updatedTemplates.list, scaffolderTaskRecord.id ] } }; this.logger.debug( `scaffolderTaskRecord with id ${scaffolderTaskRecord.id} was patched` ); } } else { migrationStatisticsReport = { ...migrationStatisticsReport, missingTemplates: { total: ++migrationStatisticsReport.missingTemplates.total, list: [ ...migrationStatisticsReport.missingTemplates.list, scaffolderTaskRecord.id ] } }; this.logger.debug( `scaffolderTaskRecord with id ${scaffolderTaskRecord.id} was not found in scaffolder DB` ); } } } catch (error) { this.logger.error( `Could not continue with backward migration, aborting...`, error ? error : void 0 ); return { status: "error", error: error ? error : void 0 }; } return { status: "SUCCESS", migrationStatisticsReport }; } } exports.TimeSaverApi = TimeSaverApi; //# sourceMappingURL=timeSaverApi.cjs.js.map