UNPKG

@amplience/dc-cli

Version:
341 lines (340 loc) 16.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.handler = exports.separateReplicas = exports.processWebhooks = exports.filterWebhooks = exports.processIndexes = exports.getIndexExports = exports.getExportedWebhooks = exports.getExportRecordForIndex = exports.enrichIndex = exports.enrichReplica = exports.registerWebhook = exports.filterIndexesById = exports.EnrichedSearchIndex = exports.EnrichedReplica = exports.EnrichedAssignedContentType = exports.equals = exports.ensureSettings = exports.assignedContentTypeEquals = exports.replicaEquals = exports.webhookEquals = exports.builder = exports.LOG_FILENAME = exports.desc = exports.command = void 0; const chalk_1 = __importDefault(require("chalk")); const dc_management_sdk_js_1 = require("dc-management-sdk-js"); const AssignedContentType_1 = require("dc-management-sdk-js/build/main/lib/model/AssignedContentType"); const SearchIndexKey_1 = require("dc-management-sdk-js/build/main/lib/model/SearchIndexKey"); const lodash_1 = require("lodash"); const table_1 = require("table"); const paginator_1 = __importDefault(require("../../common/dc-management-sdk-js/paginator")); const directory_utils_1 = require("../../common/import/directory-utils"); const log_helpers_1 = require("../../common/log-helpers"); const table_consts_1 = require("../../common/table/table.consts"); const dynamic_content_client_factory_1 = __importDefault(require("../../services/dynamic-content-client-factory")); const export_service_1 = require("../../services/export.service"); const import_service_1 = require("../../services/import.service"); const import_1 = require("./import"); const path_1 = require("path"); exports.command = 'export <dir>'; exports.desc = 'Export Search Indexes'; const LOG_FILENAME = (platform = process.platform) => (0, log_helpers_1.getDefaultLogPath)('search-index', 'export', platform); exports.LOG_FILENAME = LOG_FILENAME; const builder = (yargs) => { yargs .positional('dir', { describe: 'Output directory for the exported Search Index definitions', type: 'string' }) .option('id', { type: 'string', describe: 'The ID of a Search Index to be exported.\nIf no --id option is given, all search indexes for the hub are exported.\nA single --id option may be given to export a single Search Index.\nMultiple --id options may be given to export multiple search indexes at the same time.', requiresArg: true }) .alias('f', 'force') .option('f', { type: 'boolean', boolean: true, describe: 'Overwrite search indexes without asking.' }) .option('logFile', { type: 'string', default: exports.LOG_FILENAME, describe: 'Path to a log file to write to.', coerce: log_helpers_1.createLog }); }; exports.builder = builder; const ensureJSON = (resource) => { return resource.toJSON != null ? resource.toJSON() : resource; }; const webhookEquals = (a, b) => { if (a === undefined) { return b === undefined; } else if (b === undefined) { return false; } return (a.method === b.method && a.secret === b.secret && a.label === b.label && a.active === b.active && (0, lodash_1.isEqual)(a.customPayload, b.customPayload) && (0, lodash_1.isEqual)(a.events, b.events) && (0, lodash_1.isEqual)(a.filters, b.filters) && (0, lodash_1.isEqual)(a.handlers, b.handlers) && (0, lodash_1.isEqual)(a.headers, b.headers)); }; exports.webhookEquals = webhookEquals; const replicaEquals = (a, b, keys) => a.label === b.label && (!keys || (0, lodash_1.isEqual)(ensureJSON(a.keys), ensureJSON(b.keys))) && (0, lodash_1.isEqual)(ensureJSON(a.settings), ensureJSON(b.settings)); exports.replicaEquals = replicaEquals; const assignedContentTypeEquals = (a, b, aWebhooks, bWebhooks) => !(aWebhooks && bWebhooks) || ((0, exports.webhookEquals)(aWebhooks.get(a.webhook), bWebhooks.get(b.webhook)) && (0, exports.webhookEquals)(aWebhooks.get(a.activeContentWebhook), bWebhooks.get(b.activeContentWebhook)) && (0, exports.webhookEquals)(aWebhooks.get(a.archivedContentWebhook), bWebhooks.get(b.archivedContentWebhook))); exports.assignedContentTypeEquals = assignedContentTypeEquals; const ensureSettings = (settings) => { const result = ensureJSON(settings); result.replicas = result.replicas || []; return result; }; exports.ensureSettings = ensureSettings; const equals = (a, b, keys = true, aWebhooks, bWebhooks) => a.label === b.label && a.assignedContentTypes .map((x, i) => (0, exports.assignedContentTypeEquals)(x, b.assignedContentTypes[i], aWebhooks, bWebhooks)) .reduce((a, b) => a && b, true) && a.replicas.length == b.replicas.length && a.replicas.map((x, i) => (0, exports.replicaEquals)(x, b.replicas[i], keys)).reduce((a, b) => a && b, true) && (!keys || (0, lodash_1.isEqual)(ensureJSON(a.keys), ensureJSON(b.keys))) && (0, lodash_1.isEqual)((0, exports.ensureSettings)(a.settings), (0, exports.ensureSettings)(b.settings)); exports.equals = equals; const searchIndexList = (hub, parentId, projection) => { return (options) => hub.related.searchIndexes.list(parentId, projection, options); }; class EnrichedAssignedContentType extends AssignedContentType_1.AssignedContentType { } exports.EnrichedAssignedContentType = EnrichedAssignedContentType; class EnrichedReplica extends dc_management_sdk_js_1.SearchIndex { } exports.EnrichedReplica = EnrichedReplica; class EnrichedSearchIndex extends dc_management_sdk_js_1.SearchIndex { constructor(data) { super(data); if (this.settings && !(this.settings instanceof dc_management_sdk_js_1.SearchIndexSettings)) { this.settings = new dc_management_sdk_js_1.SearchIndexSettings(this.settings); } if (this.keys && !(this.keys instanceof SearchIndexKey_1.SearchIndexKey)) { this.keys = new SearchIndexKey_1.SearchIndexKey(this.keys); } if (this.assignedContentTypes) { this.assignedContentTypes = this.assignedContentTypes.map(x => x instanceof EnrichedAssignedContentType ? x : new EnrichedAssignedContentType(x)); } if (this.replicas) { this.replicas = this.replicas.map(x => (x instanceof EnrichedReplica ? x : new EnrichedReplica(x))); } } toJSON() { const result = super.toJSON(); if (result.settings) { result.settings = result.settings.toJSON(); } if (result.keys) { result.keys = result.keys.toJSON(); } if (result.assignedContentTypes) { result.assignedContentTypes = result.assignedContentTypes.map((type) => type.toJSON()); } if (result.replicas) { result.replicas = result.replicas.map((replica) => replica.toJSON()); } return result; } } exports.EnrichedSearchIndex = EnrichedSearchIndex; const filterIndexesById = (listToFilter, indexIdList) => { if (indexIdList.length === 0) { return listToFilter; } const unmatchedIndexUriList = indexIdList.filter(id => !listToFilter.some(index => index.id === id)); if (unmatchedIndexUriList.length > 0) { throw new Error(`The following ID(s) could not be found: [${unmatchedIndexUriList .map(u => `'${u}'`) .join(', ')}].\nNothing was exported, exiting.`); } return listToFilter.filter(index => indexIdList.some(id => index.id === id)); }; exports.filterIndexesById = filterIndexesById; const registerWebhook = (mapping, webhook) => { mapping.set(webhook.id, webhook); return webhook.id; }; exports.registerWebhook = registerWebhook; const enrichReplica = async (replica) => { const enrichedReplica = new EnrichedReplica(replica); enrichedReplica.settings = await replica.related.settings.get(); enrichedReplica.keys = await replica.related.keys.get(); return enrichedReplica; }; exports.enrichReplica = enrichReplica; const enrichIndex = async (webhooks, allReplicas, index) => { const enrichedIndex = new EnrichedSearchIndex(index); enrichedIndex.settings = await index.related.settings.get(); const types = await (0, paginator_1.default)(index.related.assignedContentTypes.list); enrichedIndex.keys = await index.related.keys.get(); const replicas = allReplicas.get(index.id); if (replicas) { enrichedIndex.replicas = await Promise.all(replicas.map(exports.enrichReplica)); } else { enrichedIndex.replicas = []; } const enrichedTypes = []; for (const type of types) { const enriched = new EnrichedAssignedContentType(type); enriched.webhook = (0, exports.registerWebhook)(webhooks, await type.related.webhook()); enriched.activeContentWebhook = (0, exports.registerWebhook)(webhooks, await type.related.activeContentWebhook()); enriched.archivedContentWebhook = (0, exports.registerWebhook)(webhooks, await type.related.archivedContentWebhook()); enrichedTypes.push(enriched); } enrichedIndex.assignedContentTypes = enrichedTypes; return enrichedIndex; }; exports.enrichIndex = enrichIndex; const getExportRecordForIndex = (index, outputDir, previouslyExportedIndexes, previouslyExportedWebhooks, webhooksBeingExported) => { const indexOfExportedIndex = Object.values(previouslyExportedIndexes).findIndex(c => c.name === index.name); if (indexOfExportedIndex < 0) { const filename = (0, export_service_1.uniqueFilenamePath)(outputDir, index.name, 'json', Object.keys(previouslyExportedIndexes)); previouslyExportedIndexes[filename] = index; return { filename: filename, status: 'CREATED', index }; } const filename = Object.keys(previouslyExportedIndexes)[indexOfExportedIndex]; const previouslyExportedIndex = Object.values(previouslyExportedIndexes)[indexOfExportedIndex]; if ((0, exports.equals)(previouslyExportedIndex, index, true, previouslyExportedWebhooks, webhooksBeingExported)) { return { filename, status: 'UP-TO-DATE', index }; } return { filename, status: 'UPDATED', index }; }; exports.getExportRecordForIndex = getExportRecordForIndex; const getExportedWebhooks = (outputDir) => { const exportedWebhooks = (0, import_service_1.loadJsonFromDirectory)((0, path_1.join)(outputDir, 'webhooks'), dc_management_sdk_js_1.Webhook); const webhookList = Object.values(exportedWebhooks); const webhooks = new Map(); for (const webhook of webhookList) { if (webhook.id) { webhooks.set(webhook.id, webhook); } } return webhooks; }; exports.getExportedWebhooks = getExportedWebhooks; const getIndexExports = (outputDir, previouslyExportedIndexes, indexesBeingExported, webhooksBeingExported) => { const allExports = []; const updatedExportsMap = []; const previouslyExportedWebhooks = (0, exports.getExportedWebhooks)(outputDir); for (const index of indexesBeingExported) { if (!index.name) { continue; } const exportRecord = (0, exports.getExportRecordForIndex)(index, outputDir, previouslyExportedIndexes, previouslyExportedWebhooks, webhooksBeingExported); allExports.push(exportRecord); if (exportRecord.status === 'UPDATED') { updatedExportsMap.push({ uri: index.name, filename: exportRecord.filename }); } } return [allExports, updatedExportsMap]; }; exports.getIndexExports = getIndexExports; const processIndexes = async (outputDir, previouslyExportedIndexes, indexesBeingExported, webhooksBeingExported, log, force) => { if (indexesBeingExported.length === 0) { (0, export_service_1.nothingExportedExit)(log, 'No search indexes to export from this hub, exiting.'); return; } const [allExports, updatedExportsMap] = (0, exports.getIndexExports)(outputDir, previouslyExportedIndexes, indexesBeingExported, webhooksBeingExported); if (allExports.length === 0 || (Object.keys(updatedExportsMap).length > 0 && !(force || (await (0, export_service_1.promptToOverwriteExports)(updatedExportsMap, log))))) { (0, export_service_1.nothingExportedExit)(log); return; } await (0, directory_utils_1.ensureDirectoryExists)(outputDir); const data = []; data.push([chalk_1.default.bold('File'), chalk_1.default.bold('Name'), chalk_1.default.bold('Result')]); for (const { filename, status, index } of allExports) { if (status !== 'UP-TO-DATE') { delete index.id; (0, export_service_1.writeJsonToFile)(filename, index); } else { indexesBeingExported.splice(indexesBeingExported.indexOf(index), 1); } data.push([filename, index.name, status]); } log.appendLine((0, table_1.table)(data, table_consts_1.streamTableOptions)); }; exports.processIndexes = processIndexes; const filterWebhooks = (webhooks, filteredIndexes) => { const filtered = new Map(); for (const index of filteredIndexes) { for (const type of index.assignedContentTypes) { filtered.set(type.webhook, webhooks.get(type.webhook)); filtered.set(type.activeContentWebhook, webhooks.get(type.activeContentWebhook)); filtered.set(type.archivedContentWebhook, webhooks.get(type.archivedContentWebhook)); } } return filtered; }; exports.filterWebhooks = filterWebhooks; const processWebhooks = async (outputDir, webhooksBeingExported, log) => { if (webhooksBeingExported.length === 0) { return; } log.appendLine('Exporting Webhooks...'); const previouslyExportedWebhooks = {}; const base = (0, path_1.join)(outputDir, 'webhooks'); await (0, directory_utils_1.ensureDirectoryExists)(base); const data = []; data.push([chalk_1.default.bold('File'), chalk_1.default.bold('Label'), chalk_1.default.bold('Result')]); for (const webhook of webhooksBeingExported) { const filename = (0, export_service_1.uniqueFilenamePath)(base, webhook.label, 'json', Object.keys(previouslyExportedWebhooks)); previouslyExportedWebhooks[filename] = webhook; (0, export_service_1.writeJsonToFile)(filename, webhook); data.push([filename, webhook.label, 'UPDATED']); } log.appendLine((0, table_1.table)(data, table_consts_1.streamTableOptions)); }; exports.processWebhooks = processWebhooks; const separateReplicas = (allIndexes) => { const storedIndexes = []; const allReplicas = new Map(); for (const index of allIndexes) { if (index.parentId == null) { storedIndexes.push(index); } else { let list = allReplicas.get(index.parentId); if (list == null) { list = []; allReplicas.set(index.parentId, list); } list.push(index); } } return { storedIndexes, allReplicas }; }; exports.separateReplicas = separateReplicas; const handler = async (argv) => { const { dir, id, logFile, force } = argv; const client = (0, dynamic_content_client_factory_1.default)(argv); const hub = await client.hubs.get(argv.hubId); const log = logFile.open(); if (!(hub._links && hub._links.hasOwnProperty('algolia-search-indexes'))) { log.warn('Search Indexes link missing for the given hub - they are likely disabled for this account.'); await log.close(); return; } const previouslyExportedIndexes = (0, import_service_1.loadJsonFromDirectory)(dir, EnrichedSearchIndex); (0, import_1.validateNoDuplicateIndexNames)(previouslyExportedIndexes); const allStoredIndexes = await (0, paginator_1.default)(searchIndexList(hub)); const { storedIndexes, allReplicas } = (0, exports.separateReplicas)(allStoredIndexes); const idArray = id ? (Array.isArray(id) ? id : [id]) : []; const filteredIndexes = (0, exports.filterIndexesById)(storedIndexes, idArray); const webhooks = new Map(); const enrichedIndexes = await Promise.all(filteredIndexes.map(index => (0, exports.enrichIndex)(webhooks, allReplicas, index))); await (0, exports.processIndexes)(dir, previouslyExportedIndexes, enrichedIndexes, webhooks, log, force || false); const filteredWebhooks = (0, exports.filterWebhooks)(webhooks, enrichedIndexes); await (0, exports.processWebhooks)(dir, Array.from(filteredWebhooks.values()), log); await log.close(); }; exports.handler = handler;