Skip to content
This repository has been archived by the owner on Feb 27, 2024. It is now read-only.

Commit

Permalink
feat: first working prototype with CLI support
Browse files Browse the repository at this point in the history
  • Loading branch information
Enngage committed Jan 16, 2020
1 parent 5501239 commit 9bf80ad
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 114 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
"build:commonjs": "npm run tsc-local -- -m commonjs --outDir _commonjs",
"build:all": "npm run build:commonjs",
"test:all": "npm run build:all",
"test:backup": "npm run build:commonjs && cd output && node ../_commonjs/cli/app --projectId=da5abe9f-fdad-4168-97cd-b3464be2ccb9 --action=backup",
"test:clean": "npm run build:commonjs && cd output && node ../_commonjs/cli/app --projectId=da5abe9f-fdad-4168-97cd-b3464be2ccb9 --action=clean",
"test:restore": "npm run build:commonjs && cd output && node ../_commonjs/cli/app --projectId=da5abe9f-fdad-4168-97cd-b3464be2ccb9 --action=restore",
"test:backup": "npm run build:commonjs && cd output && node ../_commonjs/cli/app --config=backup-config.json",
"test:clean": "npm run build:commonjs && cd output && node ../_commonjs/cli/app --config=clean-config.json",
"test:restore": "npm run build:commonjs && cd output && node ../_commonjs/cli/app --config=restore-config.json",
"ts-lint-local": "./node_modules/.bin/tslint",
"ts-lint:fix": "npm run ts-lint:check -- --fix",
"ts-lint:check": "npm run ts-lint-local -- --project ./tsconfig.json"
Expand Down
2 changes: 1 addition & 1 deletion src/clean/clean.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IProcessedItem } from '../core';
export interface ICleanConfig {
projectId: string;
apiKey: string;
processItem?: (item: IProcessedItem) => void;
onDelete?: (item: IProcessedItem) => void;
}

export interface ICleanResult {
Expand Down
4 changes: 2 additions & 2 deletions src/clean/clean.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,11 @@ export class CleanService {
}

private processItem(title: string, type: ItemType, data: any): void {
if (!this.config.processItem) {
if (!this.config.onDelete) {
return;
}

this.config.processItem({
this.config.onDelete({
data,
title,
type
Expand Down
166 changes: 91 additions & 75 deletions src/cli/app.ts
Original file line number Diff line number Diff line change
@@ -1,107 +1,123 @@
#!/usr/bin/env node
import * as fs from 'fs';
import yargs = require('yargs');

import { CleanService } from '../clean';
import { CliAction } from '../core';
import { ICliFileConfig } from '../core';
import { ExportService } from '../export';
import { ImportService } from '../import';
import { ZipService } from '../zip';

const argv = yargs.argv;

// config
const projectId: string = argv.projectId as string;
const action: string = argv.action as string;
const configFilename: string = argv.config as string;

if (!projectId) {
throw Error(`Please provide project id using 'projectId' argument`);
if (!configFilename) {
throw Error(`Please provide filename of config file using 'config' argument.`);
}

if (!action) {
throw Error(`Please provide action type using 'action' argument.`);
}
const backup = async (config: ICliFileConfig) => {
const exportService = new ExportService({
apiKey: config.apiKey,
projectId: config.projectId,
onExport: item => {
if (config.enableLog) {
console.log(`Exported: ${item.title} | ${item.type}`);
}
}
});

const zipService = new ZipService({
filename: config.zipFilename,
enableLog: config.enableLog
});

let mappedAction: CliAction;
const response = await exportService.exportAllAsync();

if (action.toLowerCase() === 'backup') {
mappedAction = 'backup';
} else if (action.toLowerCase() === 'restore') {
mappedAction = 'restore';
} else if (action.toLowerCase() === 'clean') {
mappedAction = 'clean';
} else {
throw Error(`Unsupported action type '${action}'.`);
}
await zipService.createZipAsync(response.data, response.metadata);
};

const clean = async (config: ICliFileConfig) => {
const cleanService = new CleanService({
onDelete: item => {
if (config.enableLog) {
console.log(`Deleted: ${item.title} | ${item.type}`);
}
},
projectId: config.projectId,
apiKey: config.apiKey
});

await cleanService.cleanAllAsync();
};

const exportService = new ExportService({
apiKey: sourceApiKey,
projectId: sourceProjectId
});
const restore = async (config: ICliFileConfig) => {
const zipService = new ZipService({
filename: config.zipFilename,
enableLog: config.enableLog
});

const importService = new ImportService({
processItem: item => {
console.log('imported item: ' + item.title);
},
projectId: targetProjectId,
apiKey: targetApiKey,
workflowIdForImportedItems: '00000000-0000-0000-0000-000000000000',
skip: {
languages: true
}
});
const data = await zipService.extractZipAsync();

const cleanService = new CleanService({
processItem: item => {
console.log('deleted item: ' + item.title);
},
projectId: targetProjectId,
apiKey: targetApiKey
});
const importService = new ImportService({
onImport: item => {
if (config.enableLog) {
console.log(`Imported: ${item.title} | ${item.type}`);
}
},
projectId: config.projectId,
apiKey: config.apiKey,
workflowIdForImportedItems: '00000000-0000-0000-0000-000000000000',
process: {
language: item => config.importLanguages,
contentItem: item => {
return true;
}
}
});

const zipService = new ZipService({
filename: 'test'
});
await importService.importFromSourceAsync(data);
};

const backup = async () => {
const response = await exportService.exportAllAsync();
const validateConfig = (config: any) => {
if (!config) {
throw Error(`Invalid config file`);
}

await zipService.createZipAsync(response.data, response.metadata);
const projectId = config.projectId;
const apiKey = config.apiKey;
const action = config.action;

/*
codenameTranslateHelper.replaceIdReferencesWithCodenames(response.data, response.data);
const zip = new JSZip();
zip.file('test.json', JSON.stringify(response.data));
const content = await zip.generateAsync({ type: 'nodebuffer' });
await fs.promises.writeFile(
'./processed.zip',
content
);
*/
};
if (!projectId) {
throw Error('Invalid project id');
}

const clean = async () => {
await cleanService.cleanAllAsync();
};
if (!apiKey) {
throw Error('Invalid api key');
}

const restore = async () => {
// const response = await exportService.exportAllAsync();
if (!action) {
throw Error('Invalid action');
}
};

const data = await zipService.extractZipAsync();
const process = async () => {
const configFile = await fs.promises.readFile(`./${configFilename}`);

await importService.importFromSourceAsync(data);
};
const config = JSON.parse(configFile.toString()) as ICliFileConfig;

if (mappedAction === 'backup') {
backup();
}
validateConfig(config);

if (mappedAction === 'clean') {
clean();
}
if (config.action === 'backup') {
backup(config);
} else if (config.action === 'clean') {
clean(config);
} else if (config.action === 'restore') {
restore(config);
} else {
throw Error(`Invalid action`);
}
};

if (mappedAction === 'restore') {
restore();
}
process();
8 changes: 8 additions & 0 deletions src/cli/sample-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"projectId": "x",
"apiKey": "y",
"zipFilename": "backup",
"action": "backup",
"enableLog": true,
"importLanguages": false
}
9 changes: 9 additions & 0 deletions src/core/core.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ import {
AssetFolderContracts,
} from '@kentico/kontent-management';

export interface ICliFileConfig {
projectId: string;
apiKey: string;
action: CliAction;
zipFilename: string;
enableLog: boolean;
importLanguages: boolean;
}

export type CliAction = 'backup' | 'restore' | 'clean';
export type ItemType =
| 'taxonomy'
Expand Down
11 changes: 7 additions & 4 deletions src/export/export.models.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import {
AssetContracts,
AssetFolderContracts,
ContentItemContracts,
ContentTypeContracts,
ContentTypeSnippetContracts,
TaxonomyContracts,
LanguageVariantContracts,
LanguageContracts,
AssetContracts,
AssetFolderContracts,
LanguageVariantContracts,
TaxonomyContracts,
} from '@kentico/kontent-management';

import { IProcessedItem } from '../core';

export interface IExportConfig {
projectId: string;
apiKey: string;
onExport?: (item: IProcessedItem) => void;
}

export interface IExportData {
Expand Down
22 changes: 22 additions & 0 deletions src/export/export.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@kentico/kontent-management';

import { IExportAllResult, IExportConfig, IExportData } from './export.models';
import { ItemType } from '../core';

export class ExportService {
private readonly client: IManagementClient;
Expand Down Expand Up @@ -48,36 +49,43 @@ export class ExportService {

public async exportAssetsAsync(): Promise<AssetContracts.IAssetModelContract[]> {
const response = await this.client.listAssets().toPromise();
response.data.items.forEach(m => this.processItem(m.fileName, 'asset', m));
return response.data.items.map(m => m._raw);
}

public async exportAssetFoldersAsync(): Promise<AssetFolderContracts.IAssetFolderContract[]> {
const response = await this.client.listAssetFolders().toPromise();
response.data.items.forEach(m => this.processItem(m.name, 'assetFolder', m));
return response.data.items.map(m => m._raw);
}

public async exportLanguagesAsync(): Promise<LanguageContracts.ILanguageModelContract[]> {
const response = await this.client.listLanguages().toPromise();
response.data.items.forEach(m => this.processItem(m.name, 'language', m));
return response.data.items.map(m => m._raw);
}

public async exportTaxonomiesAsync(): Promise<TaxonomyContracts.ITaxonomyContract[]> {
const response = await this.client.listTaxonomies().toPromise();
response.data.taxonomies.forEach(m => this.processItem(m.name, 'taxonomy', m));
return response.data.taxonomies.map(m => m._raw);
}

public async exportContentTypeSnippetsAsync(): Promise<ContentTypeSnippetContracts.IContentTypeSnippetContract[]> {
const response = await this.client.listContentTypeSnippets().toAllPromise();
response.data.items.forEach(m => this.processItem(m.name, 'contentTypeSnippet', m));
return response.data.items.map(m => m._raw);
}

public async exportContentTypesAsync(): Promise<ContentTypeContracts.IContentTypeContract[]> {
const response = await this.client.listContentTypes().toAllPromise();
response.data.items.forEach(m => this.processItem(m.name, 'contentType', m));
return response.data.items.map(m => m._raw);
}

public async exportContentItemsAsync(): Promise<ContentItemContracts.IContentItemModelContract[]> {
const response = await this.client.listContentItems().toAllPromise();
response.data.items.forEach(m => this.processItem(m.name, 'contentItem', m));
return response.data.items.map(m => m._raw);
}

Expand Down Expand Up @@ -106,6 +114,20 @@ export class ExportService {
);
}

languageVariants.forEach(m => this.processItem(m.item.id?.toString() ?? '-', 'languageVariant', m));

return languageVariants;
}

private processItem(title: string, type: ItemType, data: any): void {
if (!this.config.onExport) {
return;
}

this.config.onExport({
data,
title,
type
});
}
}
4 changes: 2 additions & 2 deletions src/import/import.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class ImportHelper {
codenameTranslateHelper.replaceIdReferencesWithCodenames(sourceData.importData, sourceData.importData);

// flatten data
const items = this.flattenExportData(sourceData);
const items = this.flattenSourceData(sourceData);

return {
orderedImportItems: items,
Expand Down Expand Up @@ -54,7 +54,7 @@ export class ImportHelper {
return filteredDeps;
}

private flattenExportData(sourceData: IImportSource): IPreparedImportItem[] {
private flattenSourceData(sourceData: IImportSource): IPreparedImportItem[] {
return [
...sourceData.importData.taxonomies.map(m => {
return <IPreparedImportItem> {
Expand Down
Loading

0 comments on commit 9bf80ad

Please sign in to comment.