@amplience/dc-cli
Version:
Dynamic Content CLI Tool
255 lines (254 loc) • 12.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = exports.processContentTypes = exports.synchronizeContentTypeRepositories = exports.doSync = exports.doUpdate = exports.doCreate = exports.filterContentTypesById = exports.validateNoDuplicateContentTypeUris = exports.storedContentTypeMapper = exports.ContentTypeWithRepositoryAssignments = exports.builder = exports.LOG_FILENAME = exports.desc = exports.command = void 0;
const dynamic_content_client_factory_1 = __importDefault(require("../../services/dynamic-content-client-factory"));
const paginator_1 = __importDefault(require("../../common/dc-management-sdk-js/paginator"));
const dc_management_sdk_js_1 = require("dc-management-sdk-js");
const lodash_1 = require("lodash");
const table_1 = require("table");
const chalk_1 = __importDefault(require("chalk"));
const import_service_1 = require("../../services/import.service");
const table_consts_1 = require("../../common/table/table.consts");
const log_helpers_1 = require("../../common/log-helpers");
const progress_bar_1 = require("../../common/progress-bar/progress-bar");
exports.command = 'import <dir>';
exports.desc = 'Import Content Types';
const LOG_FILENAME = (platform = process.platform) => (0, log_helpers_1.getDefaultLogPath)('type', 'import', platform);
exports.LOG_FILENAME = LOG_FILENAME;
let notFoundRepositories = [];
const builder = (yargs) => {
yargs.positional('dir', {
describe: 'Path to Content Type definitions',
type: 'string'
});
yargs.option('sync', {
describe: 'Automatically sync Content Type schema',
type: 'boolean',
default: false
});
yargs.option('logFile', {
type: 'string',
default: exports.LOG_FILENAME,
describe: 'Path to a log file to write to.',
coerce: log_helpers_1.createLog
});
yargs.option('skipAssign', {
describe: 'Skip assigning content types to repositories.',
type: 'boolean',
default: false
});
};
exports.builder = builder;
class ContentTypeWithRepositoryAssignments extends dc_management_sdk_js_1.ContentType {
}
exports.ContentTypeWithRepositoryAssignments = ContentTypeWithRepositoryAssignments;
const storedContentTypeMapper = (contentType, storedContentTypes) => {
const found = storedContentTypes.find(storedContentType => storedContentType.contentTypeUri === contentType.contentTypeUri);
const mutatedContentType = found ? { ...contentType, id: found.id } : contentType;
return new ContentTypeWithRepositoryAssignments(mutatedContentType);
};
exports.storedContentTypeMapper = storedContentTypeMapper;
const validateNoDuplicateContentTypeUris = (importedContentTypes) => {
const uriToFilenameMap = new Map();
for (const [filename, contentType] of Object.entries(importedContentTypes)) {
if (contentType.contentTypeUri) {
const otherFilenames = uriToFilenameMap.get(contentType.contentTypeUri) || [];
if (filename) {
uriToFilenameMap.set(contentType.contentTypeUri, [...otherFilenames, filename]);
}
}
}
const uniqueDuplicateUris = [];
uriToFilenameMap.forEach((filenames, uri) => {
if (filenames.length > 1) {
uniqueDuplicateUris.push([uri, filenames]);
}
});
if (uniqueDuplicateUris.length > 0) {
throw new Error(`Content Types must have unique uri values. Duplicate values found:-\n${uniqueDuplicateUris
.map(([uri, filenames]) => ` uri: '${uri}' in files: [${filenames.map(f => `'${f}'`).join(', ')}]`)
.join('\n')}`);
}
};
exports.validateNoDuplicateContentTypeUris = validateNoDuplicateContentTypeUris;
const filterContentTypesById = (idFilter, importedContentTypes) => {
for (const [filename, contentType] of Object.entries(importedContentTypes)) {
if (contentType.contentTypeUri) {
if (idFilter.indexOf(contentType.id) === -1) {
delete importedContentTypes[filename];
}
}
}
};
exports.filterContentTypesById = filterContentTypesById;
const doCreate = async (hub, contentType, log) => {
try {
const result = await hub.related.contentTypes.register(new dc_management_sdk_js_1.ContentType(contentType));
log.addAction('CREATE', `${result.id}`);
return result;
}
catch (err) {
throw new Error(`Error registering content type ${contentType.contentTypeUri}: ${err.message || err}`);
}
};
exports.doCreate = doCreate;
const equals = (a, b) => a.id === b.id && a.contentTypeUri === b.contentTypeUri && (0, lodash_1.isEqual)(a.settings, b.settings);
const doUpdate = async (client, contentType, log) => {
let retrievedContentType;
try {
retrievedContentType = await client.contentTypes.get(contentType.id || '');
}
catch (err) {
throw new Error(`Error unable to get content type ${contentType.id}: ${err.message}`);
}
if (retrievedContentType.status === dc_management_sdk_js_1.Status.ARCHIVED) {
try {
retrievedContentType = await retrievedContentType.related.unarchive();
}
catch (err) {
throw new Error(`Error unable unarchive content type ${contentType.id}: ${err.message}`);
}
}
contentType.settings = { ...retrievedContentType.settings, ...contentType.settings };
let updatedContentType;
if (equals(retrievedContentType, contentType)) {
return { contentType: retrievedContentType, updateStatus: import_service_1.UpdateStatus.SKIPPED };
}
try {
updatedContentType = await retrievedContentType.related.update(contentType);
log.addAction('UPDATE', `${contentType.id}`);
return { contentType: updatedContentType, updateStatus: import_service_1.UpdateStatus.UPDATED };
}
catch (err) {
throw new Error(`Error updating content type ${contentType.id}: ${err.message || err}`);
}
};
exports.doUpdate = doUpdate;
const doSync = async (client, contentType) => {
let retrievedContentType;
try {
retrievedContentType = await client.contentTypes.get(contentType.id || '');
}
catch (err) {
throw new Error(`Error unable to get content type ${contentType.id}: ${err.message}`);
}
try {
await retrievedContentType.related.contentTypeSchema.update();
return { contentType: retrievedContentType, updateStatus: import_service_1.UpdateStatus.UPDATED };
}
catch (err) {
throw new Error(`Error updating the content type schema of the content type ${contentType.id}: ${err.message}`);
}
};
exports.doSync = doSync;
const validateRepositories = (repositories) => Array.isArray(repositories) && repositories.every(repo => typeof repo === 'string');
const synchronizeContentTypeRepositories = async (contentType, namedRepositories) => {
if (!validateRepositories(contentType.repositories)) {
throw new Error('Invalid format supplied for repositories. Please provide an array of repository names');
}
const assignedRepositories = new Map();
namedRepositories.forEach(contentRepository => {
const contentRepositoryContentTypes = contentRepository.contentTypes || [];
contentRepositoryContentTypes.forEach(assignedContentTypes => {
if (assignedContentTypes.hubContentTypeId === contentType.id) {
assignedRepositories.set(contentRepository.name || '', contentRepository);
}
});
});
const contentTypeId = contentType.id || '';
const definedContentRepository = (0, lodash_1.intersection)(contentType.repositories || [], [...namedRepositories.keys()]).filter((value, index, array) => array.indexOf(value) === index);
notFoundRepositories = notFoundRepositories.concat((0, lodash_1.difference)(contentType.repositories, [...namedRepositories.keys()]));
let changedAssignment = false;
for (const repo of definedContentRepository) {
if (!assignedRepositories.has(repo)) {
const contentRepository = namedRepositories.get(repo);
if (!contentRepository) {
throw new Error(`Unable to find a Content Repository named: ${repo}`);
}
await contentRepository.related.contentTypes.assign(contentTypeId);
changedAssignment = true;
}
else {
assignedRepositories.delete(repo);
}
}
for (const assignedRepository of assignedRepositories.values()) {
await assignedRepository.related.contentTypes.unassign(contentTypeId);
changedAssignment = true;
}
return changedAssignment;
};
exports.synchronizeContentTypeRepositories = synchronizeContentTypeRepositories;
const processContentTypes = async (contentTypes, client, hub, sync, log, skipAssign = false) => {
const contentRepositoryList = await (0, paginator_1.default)(hub.related.contentRepositories.list, {});
const namedRepositories = new Map(contentRepositoryList.map(value => [value.name || '', value]));
const progress = (0, progress_bar_1.progressBar)(contentTypes.length, 0, { title: 'Importing content types' });
const data = [[chalk_1.default.bold('ID'), chalk_1.default.bold('Schema ID'), chalk_1.default.bold('Result')]];
for (const contentType of contentTypes) {
let status;
let contentTypeResult;
if (contentType.id) {
status = 'UP-TO-DATE';
const result = await (0, exports.doUpdate)(client, contentType, log);
if (result.updateStatus === import_service_1.UpdateStatus.UPDATED) {
status = 'UPDATED';
}
contentTypeResult = result.contentType;
if (sync) {
const syncResult = await (0, exports.doSync)(client, contentType);
if (syncResult.updateStatus === import_service_1.UpdateStatus.UPDATED) {
status = 'UPDATED';
}
}
}
else {
contentTypeResult = await (0, exports.doCreate)(hub, contentType, log);
status = 'CREATED';
}
if (contentType.repositories &&
!skipAssign &&
(await (0, exports.synchronizeContentTypeRepositories)(new ContentTypeWithRepositoryAssignments({ ...contentType, ...contentTypeResult }), namedRepositories))) {
status = contentType.id ? 'UPDATED' : 'CREATED';
}
progress.increment();
data.push([contentTypeResult.id || 'UNKNOWN', contentType.contentTypeUri || '', status]);
}
progress.stop();
log.appendLine((0, table_1.table)(data, table_consts_1.streamTableOptions));
if (!skipAssign && notFoundRepositories.length) {
log.appendLine('\nThe following Repositories were not found in destination Hub:');
(0, lodash_1.uniq)(notFoundRepositories).map(name => log.appendLine(` ${name}`));
}
else if (skipAssign) {
log.appendLine('\nContent types were not automatically registered to the repositories because of --skipAssign argument.');
}
};
exports.processContentTypes = processContentTypes;
const handler = async (argv, idFilter) => {
const { dir, sync, logFile, skipAssign } = argv;
const log = logFile.open();
const importedContentTypes = (0, import_service_1.loadJsonFromDirectory)(dir, ContentTypeWithRepositoryAssignments);
if (Object.keys(importedContentTypes).length === 0) {
log.appendLine(`No content types found in ${dir}`);
await log.close();
return;
}
(0, exports.validateNoDuplicateContentTypeUris)(importedContentTypes);
if (idFilter) {
(0, exports.filterContentTypesById)(idFilter, importedContentTypes);
}
const client = (0, dynamic_content_client_factory_1.default)(argv);
const hub = await client.hubs.get(argv.hubId);
const activeContentTypes = await (0, paginator_1.default)(hub.related.contentTypes.list, { status: dc_management_sdk_js_1.Status.ACTIVE });
const archivedContentTypes = await (0, paginator_1.default)(hub.related.contentTypes.list, { status: dc_management_sdk_js_1.Status.ARCHIVED });
const storedContentTypes = [...activeContentTypes, ...archivedContentTypes];
for (const [filename, importedContentType] of Object.entries(importedContentTypes)) {
importedContentTypes[filename] = (0, exports.storedContentTypeMapper)(importedContentType, storedContentTypes);
}
await (0, exports.processContentTypes)(Object.values(importedContentTypes), client, hub, sync, log, skipAssign);
await log.close();
};
exports.handler = handler;