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

Commit

Permalink
feat: implements base import / export story, cleans asset folders, tr…
Browse files Browse the repository at this point in the history
…anslates ids of imported data in rich text elems
  • Loading branch information
Enngage committed Jan 15, 2020
1 parent e781d8b commit 6f4623a
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 64 deletions.
Binary file modified output/test.zip
Binary file not shown.
11 changes: 3 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
],
"license": "MIT",
"dependencies": {
"@kentico/kontent-management": "0.3.10",
"@kentico/kontent-management": "0.3.11",
"jszip": "3.2.2",
"rxjs": "6.5.4",
"yargs": "15.1.0",
Expand Down
106 changes: 68 additions & 38 deletions src/clean/clean.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IManagementClient, ManagementClient } from '@kentico/kontent-management';
import { AssetFolderModels, IManagementClient, ManagementClient } from '@kentico/kontent-management';

import { ItemType } from '../core';
import { ICleanConfig, ICleanResult } from './clean.models';
Expand All @@ -14,18 +14,24 @@ export class CleanService {
}

public async cleanAllAsync(): Promise<ICleanResult> {
await this.cleanContentItemsAsync();
await this.cleanContentTypesAsync();
await this.cleanContentTypeSnippetsAsync();
await this.cleanTaxonomiesAsync();
await this.cleanAssetsAsync();

return {
metadata: {
projectId: this.config.projectId,
timestamp: new Date()
}
};
try {
await this.cleanContentItemsAsync();
await this.cleanContentTypesAsync();
await this.cleanContentTypeSnippetsAsync();
await this.cleanTaxonomiesAsync();
await this.cleanAssetsAsync();
await this.cleanAssetFoldersAsync();

return {
metadata: {
projectId: this.config.projectId,
timestamp: new Date()
}
};
} catch (err) {
console.log(err);
throw err;
}
}

public async cleanTaxonomiesAsync(): Promise<void> {
Expand Down Expand Up @@ -88,12 +94,36 @@ export class CleanService {
}
}

public async cleanAssetFoldersAsync(): Promise<void> {
const assetFolders = (await this.client.listAssetFolders().toPromise()).data.items;

if (assetFolders.length) {
await this.client
.modifyAssetFolders()
.withData(
assetFolders.map(m => {
return <AssetFolderModels.IModifyAssetFoldersData>{
op: 'remove',
reference: {
id: m.id
}
};
})
)
.toPromise()
.then(response => {
for (const folder of assetFolders) {
this.processItem(folder.name, 'assetFolder', folder);
}
})
.catch(error => this.handleCleanError(error));
}
}

public async cleanContentItemsAsync(): Promise<void> {
const contentItems = (await this.client.listContentItems().toAllPromise()).data.items;

for (const contentItem of contentItems) {
await this.cleanLanguageVariantsAsync(contentItem.id);

await this.client
.deleteContentItem()
.byItemId(contentItem.id)
Expand All @@ -106,31 +136,31 @@ export class CleanService {
}

public async cleanLanguageVariantsAsync(contentItemId: string): Promise<void> {
const languageVariants = (
await this.client
.listLanguageVariantsOfItem()
.byItemId(contentItemId)
.toPromise()
).data.items;

for (const languageVariant of languageVariants) {
const languageId = languageVariant.language.id;
const itemId = contentItemId;

if (!languageId) {
throw Error(`Missing language id for item '${contentItemId}'`);
}
const languageVariants = (
await this.client
.listLanguageVariantsOfItem()
.byItemId(contentItemId)
.toPromise()
).data.items;

await this.client
.deleteLanguageVariant()
.byItemId(itemId)
.byLanguageId(languageId)
.toPromise()
.then(m => {
this.processItem(itemId, 'languageVariant', languageVariant);
})
.catch(error => this.handleCleanError(error));
for (const languageVariant of languageVariants) {
const languageId = languageVariant.language.id;
const itemId = contentItemId;

if (!languageId) {
throw Error(`Missing language id for item '${contentItemId}'`);
}

await this.client
.deleteLanguageVariant()
.byItemId(itemId)
.byLanguageId(languageId)
.toPromise()
.then(m => {
this.processItem(itemId, 'languageVariant', languageVariant);
})
.catch(error => this.handleCleanError(error));
}
}

private handleCleanError(error: any): void {
Expand Down
3 changes: 2 additions & 1 deletion src/core/core.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export type ItemType =
| 'contentItem'
| 'languageVariant'
| 'language'
| 'asset';
| 'asset'
| 'assetFolder';

export type ValidImportModel =
| ContentTypeModels.ContentType
Expand Down
48 changes: 43 additions & 5 deletions src/core/id-translate-helper.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@

import { ValidImportContract, ValidImportModel, IImportItemResult } from './core.models';
import { IImportItemResult, ValidImportContract, ValidImportModel } from './core.models';

export class IdTranslateHelper {
public replaceIdReferencesWithNewId(
data: any,
items: IImportItemResult<ValidImportContract, ValidImportModel>[]
items: IImportItemResult<ValidImportContract, ValidImportModel>[],
): void {
if (data) {
if (Array.isArray(data)) {
Expand All @@ -14,12 +13,15 @@ export class IdTranslateHelper {
} else {
for (const key of Object.keys(data)) {
const val = (data as any)[key];
if (typeof val === 'string' && val.startsWith('<p>')) {
// replace string with updated one
const newData = this.replaceIdsInRichText(val, items);
data[key] = newData;
}
if (key.toLowerCase() === 'id') {
const id = (data as any).id;

const newId = this.tryFindNewId(id, items);

// replace old id with new
if (newId) {
data.id = newId;
}
Expand All @@ -33,6 +35,42 @@ export class IdTranslateHelper {
}
}

private replaceIdsInRichText(
text: string,
items: IImportItemResult<ValidImportContract, ValidImportModel>[]
): string {
const itemId = { regex: /data-item-id=\"(.*?)\"/g, attr: 'data-item-id' };
const assetId = { regex: /data-asset-id=\"(.*?)\"/g, attr: 'data-asset-id' };
const imageId = { regex: /data-image-id=\"(.*?)\"/g, attr: 'data-image-id' };
const dataId = { regex: /data-id=\"(.*?)\"/g, attr: 'data-id' };

text = this.replaceTextWithRegex(itemId.regex, text, itemId.attr, items);
text = this.replaceTextWithRegex(assetId.regex, text, assetId.attr, items);
text = this.replaceTextWithRegex(imageId.regex, text, imageId.attr, items);
text = this.replaceTextWithRegex(dataId.regex, text, dataId.attr, items);

return text;
}

private replaceTextWithRegex(
regex: RegExp,
text: string,
replaceAttr: string,
items: IImportItemResult<ValidImportContract, ValidImportModel>[]
): string {
return text.replace(regex, (a, b) => {
if (b) {
const newId = this.tryFindNewId(b, items);

if (newId) {
return `${replaceAttr}="${newId}"`;
}
}

return a;
});
}

private tryFindNewId(
id: string,
items: IImportItemResult<ValidImportContract, ValidImportModel>[]
Expand Down
27 changes: 18 additions & 9 deletions src/export/export.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ export class ExportService {
}

public async exportAllAsync(): Promise<IExportAllResult> {
const contentItems = await this.exportContentItemsAsync();
const contentTypes = await this.exportContentTypesAsync();

const data: IExportData = {
contentTypes: await this.exportContentTypesAsync(),
contentTypes,
contentTypeSnippets: await this.exportContentTypeSnippetsAsync(),
taxonomies: await this.exportTaxonomiesAsync(),
contentItems,
languageVariants: await this.exportLanguageVariantsAsync(contentItems.map(m => m.id)),
contentItems: await this.exportContentItemsAsync(),
languageVariants: await this.exportLanguageVariantsAsync(contentTypes.map(m => m.id)),
assets: await this.exportAssetsAsync(),
languages: await this.exportLanguagesAsync()
};
Expand Down Expand Up @@ -75,16 +75,25 @@ export class ExportService {
}

public async exportLanguageVariantsAsync(
contentItemIds: string[]
typeIds: string[]
): Promise<LanguageVariantContracts.ILanguageVariantModelContract[]> {
const languageVariants: LanguageVariantContracts.ILanguageVariantModelContract[] = [];
const languageVariants: LanguageVariantContracts.ILanguageVariantModelWithComponentsContract[] = [];

for (const itemId of contentItemIds) {
for (const typeId of typeIds) {
languageVariants.push(
...(
await this.client
.listLanguageVariantsOfItem()
.byItemId(itemId)
.listLanguageVariantsOfContentTypeWithComponents()
.byTypeId(typeId)
.toPromise()
).data.items.map(m => m._raw)
);

languageVariants.push(
...(
await this.client
.listLanguageVariantsOfContentType()
.byTypeId(typeId)
.toPromise()
).data.items.map(m => m._raw)
);
Expand Down
1 change: 0 additions & 1 deletion src/import/import.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export class ImportService {
binaryFiles: IBinaryFile[],
currentItems: IImportItemResult<ValidImportContract, ValidImportModel>[]
): Promise<IImportItemResult<ValidImportContract, ValidImportModel>[]> {
console.log('importing item', item.codename);
if (item.type === 'contentType') {
return await this.importContentTypesAsync([item.item]);
} else if (item.type === 'taxonomy') {
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"alwaysStrict": true,
"forceConsistentCasingInFileNames": true,
"noUnusedParameters": false,
"noUnusedLocals": true,
"noUnusedLocals": false,
"strictFunctionTypes": true,
"noImplicitAny": true,
"typeRoots": [
Expand Down

0 comments on commit 6f4623a

Please sign in to comment.