Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions packages/contentstack-audit/src/audit-base-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import { join, resolve } from 'path';
import cloneDeep from 'lodash/cloneDeep';
import { cliux, sanitizePath, ux } from '@contentstack/cli-utilities';
import { createWriteStream, existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from 'fs';

import config from './config';
import { print } from './util/log';
import { auditMsg } from './messages';
import { BaseCommand } from './base-command';
import { Entries, GlobalField, ContentType, Extensions, Workflows, Assets } from './modules';
import { Entries, GlobalField, ContentType, Extensions, Workflows, Assets, FieldRule } from './modules';
import {
CommandNames,
ContentTypeStruct,
Expand Down Expand Up @@ -60,7 +59,8 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
missingTitleFields,
missingRefInCustomRoles,
missingEnvLocalesInAssets,
missingEnvLocalesInEntries
missingEnvLocalesInEntries,
missingFieldRules
} = await this.scanAndFix();

this.showOutputOnScreen([
Expand All @@ -70,6 +70,7 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
]);
this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Extensions', missingRefs: missingCtRefsInExtensions }]);
this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Workflows', missingRefs: missingCtRefsInWorkflow }]);

this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Entries Select Field', missingRefs: missingSelectFeild }]);
this.showOutputOnScreenWorkflowsAndExtension([
{ module: 'Entries Mandatory Field', missingRefs: missingMandatoryFields },
Expand All @@ -80,6 +81,8 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Custom Roles', missingRefs: missingRefInCustomRoles }]);
this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Assets', missingRefs: missingEnvLocalesInAssets }]);
this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Entries Missing Locale and Environments', missingRefs: missingEnvLocalesInEntries }])
this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Field Rules', missingRefs: missingFieldRules }])

if (
!isEmpty(missingCtRefs) ||
!isEmpty(missingGfRefs) ||
Expand All @@ -90,7 +93,8 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
!isEmpty(missingTitleFields) ||
!isEmpty(missingRefInCustomRoles) ||
!isEmpty(missingEnvLocalesInAssets) ||
!isEmpty(missingEnvLocalesInEntries)
!isEmpty(missingEnvLocalesInEntries) ||
!isEmpty(missingSelectFeild)
) {
if (this.currentCommand === 'cm:stacks:audit') {
this.log(this.$t(auditMsg.FINAL_REPORT_PATH, { path: this.sharedConfig.reportPath }), 'warn');
Expand Down Expand Up @@ -120,7 +124,8 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
!isEmpty(missingSelectFeild) ||
!isEmpty(missingRefInCustomRoles) ||
!isEmpty(missingEnvLocalesInAssets) ||
!isEmpty(missingEnvLocalesInEntries)
!isEmpty(missingEnvLocalesInEntries) ||
!isEmpty(missingFieldRules)
);
}

Expand All @@ -143,7 +148,8 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
missingTitleFields,
missingRefInCustomRoles,
missingEnvLocalesInAssets,
missingEnvLocalesInEntries;
missingEnvLocalesInEntries,
missingFieldRules;

for (const module of this.sharedConfig.flags.modules || this.sharedConfig.modules) {
print([
Expand Down Expand Up @@ -211,6 +217,10 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
missingRefInCustomRoles = await new CustomRoles(cloneDeep(constructorParam)).run();
await this.prepareReport(module, missingRefInCustomRoles);
break;
case 'field-rules':
missingFieldRules = await new FieldRule(cloneDeep(constructorParam)).run();
await this.prepareReport(module, missingFieldRules);
break;
}

print([
Expand Down Expand Up @@ -238,7 +248,8 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
missingTitleFields,
missingRefInCustomRoles,
missingEnvLocalesInAssets,
missingEnvLocalesInEntries
missingEnvLocalesInEntries,
missingFieldRules
};
}

Expand Down Expand Up @@ -405,7 +416,8 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
key === 'content_types' ||
key === 'branches' ||
key === 'missingCTSelectFieldValues' ||
key === 'missingFieldUid'
key === 'missingFieldUid' ||
key === 'action'
) {
return chalk.red(typeof row[key] === 'object' ? JSON.stringify(row[key]) : row[key]);
} else {
Expand Down Expand Up @@ -435,7 +447,7 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
* @returns The function `prepareReport` returns a Promise that resolves to `void`.
*/
prepareReport(
moduleName: keyof typeof config.moduleConfig | keyof typeof config.ReportTitleForEntries,
moduleName: keyof typeof config.moduleConfig | keyof typeof config.ReportTitleForEntries | 'field-rules',
listOfMissingRefs: Record<string, any>,
): Promise<void> {
if (isEmpty(listOfMissingRefs)) return Promise.resolve(void 0);
Expand All @@ -462,7 +474,7 @@ export abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseComma
* @returns The function `prepareCSV` returns a Promise that resolves to `void`.
*/
prepareCSV(
moduleName: keyof typeof config.moduleConfig | keyof typeof config.ReportTitleForEntries,
moduleName: keyof typeof config.moduleConfig | keyof typeof config.ReportTitleForEntries | 'field-rules',
listOfMissingRefs: Record<string, any>,
): Promise<void> {
if (Object.keys(config.moduleConfig).includes(moduleName) || config.feild_level_modules.includes(moduleName)) {
Expand Down
33 changes: 25 additions & 8 deletions packages/contentstack-audit/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@ const config = {
showTerminalOutput: true,
skipRefs: ['sys_assets'],
skipFieldTypes: ['taxonomy', 'group'],
modules: ['content-types', 'global-fields', 'entries', 'extensions', 'workflows', 'custom-roles', 'assets'],
modules: [
'content-types',
'global-fields',
'entries',
'extensions',
'workflows',
'custom-roles',
'assets',
'field-rules',
],
'fix-fields': ['reference', 'global_field', 'json:rte', 'json:extension', 'blocks', 'group', 'content_types'],
moduleConfig: {
'content-types': {
Expand Down Expand Up @@ -40,16 +49,16 @@ const config = {
dirName: 'custom-roles',
fileName: 'custom-roles.json',
},
'assets': {
assets: {
name: 'assets',
dirName: 'assets',
fileName: 'assets.json',
},
'environments': {
environments: {
name: 'environments',
dirName: 'environments',
fileName: 'environments.json',
}
},
},
entries: {
systemKeys: [
Expand Down Expand Up @@ -94,17 +103,25 @@ const config = {
'publish_locale',
'publish_environment',
'asset_uid',
'selectedValue'
'selectedValue',
'ct_uid',
'action',
],
ReportTitleForEntries: {
Entries_Select_feild: 'Entries_Select_feild',
Entries_Mandatory_feild: 'Entries_Mandatory_feild',
Entries_Title_feild: 'Entries_Title_feild',
Entry_Missing_Locale_and_Env: 'Entry_Missing_Locale_and_Env',
Entry_Missing_Locale_and_Env_in_Publish_Details: 'Entry_Missing_Locale_and_Env_in_Publish_Details'
Entry_Missing_Locale_and_Env_in_Publish_Details: 'Entry_Missing_Locale_and_Env_in_Publish_Details',
},
feild_level_modules: ['Entries_Title_feild', 'Entries_Mandatory_feild', 'Entries_Select_feild', 'Entry_Missing_Locale_and_Env_in_Publish_Details'],
fixSelectField: false
feild_level_modules: [
'Entries_Title_feild',
'Entries_Mandatory_feild',
'Entries_Select_feild',
'Entry_Missing_Locale_and_Env_in_Publish_Details',
'field-rules',
],
fixSelectField: false,
};

export default config;
5 changes: 5 additions & 0 deletions packages/contentstack-audit/src/messages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ const auditMsg = {
CT_REFERENCE_FIELD: `The mentioned Reference field is not Array field reference is '{reference_to}' having display name '{display_name}''`,
ASSET_NOT_EXIST: `The publish_details either does not exist or is not an array for asset uid '{uid}'`,
ENTRY_PUBLISH_DETAILS_NOT_EXIST: `The publish_details either does not exist or is not an array for entry uid '{uid}'`,
FIELD_RULE_CONDITION_ABSENT: `The operand field '{condition_field}' is not present in the schema of the content-type {ctUid}`,
FIELD_RULE_TARGET_ABSENT: `The target field '{target_field}' is not present in the schema of the content-type {ctUid}`,
FIELD_RULE_CONDITION_SCAN_MESSAGE: `Completed Scanning of Field Rule '{num}' condition of Content-type '{ctUid}'`,
FIELD_RULE_TARGET_SCAN_MESSAGE: `Completed Scanning of Field Rule '{num}' target of Content-type '{ctUid}'`
};

const auditFixMsg = {
Expand All @@ -56,6 +60,7 @@ const auditFixMsg = {
ENTRY_MANDATORY_FIELD_FIX: `Removing the publish details from the entry with UID '{uid}' in Locale '{locale}'...`,
ENTRY_SELECT_FIELD_FIX: `Adding the value '{value}' in the select field of entry UID '{uid}'...`,
ASSET_FIX: `Fixed publish detials for Asset with UID '{uid}'`,
FIELD_RULE_FIX_MESSAGE: `Fixed Field Rule '{num}' target of Content-type '{ctUid}`,
};

const messages: typeof errors &
Expand Down
16 changes: 10 additions & 6 deletions packages/contentstack-audit/src/modules/content-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default class ContentType {
protected schema: ContentTypeStruct[] = [];
protected missingRefs: Record<string, any> = {};
public moduleName: keyof typeof auditConfig.moduleConfig;

public f:any = []
Comment thread
cs-raj marked this conversation as resolved.
Outdated
constructor({ log, fix, config, moduleName, ctSchema, gfSchema }: ModuleConstructorParam & CtConstructorParam) {
this.log = log;
this.config = config;
Expand Down Expand Up @@ -91,7 +91,7 @@ export default class ContentType {
this.currentTitle = schema.title;
this.missingRefs[this.currentUid] = [];
const { uid, title } = schema;
await this.lookForReference([{ uid, name: title }], schema);
await this.lookForReference([{ uid, name: title }], schema, null);
this.log(
$t(auditMsg.SCAN_CT_SUCCESS_MSG, { title, module: this.config.moduleConfig[this.moduleName].name }),
'info',
Expand Down Expand Up @@ -179,14 +179,18 @@ export default class ContentType {
async lookForReference(
tree: Record<string, unknown>[],
field: ContentTypeStruct | GlobalFieldDataType | ModularBlockType | GroupFieldDataType,
parent: any = null
Comment thread
cs-raj marked this conversation as resolved.
Outdated
): Promise<void> {
const fixTypes = this.config.flags['fix-only'] ?? this.config['fix-fields'];

if (this.fix) {
field.schema = this.runFixOnSchema(tree, field.schema as ContentTypeSchemaType[]);
}

for (let child of field.schema ?? []) {
if(parent) {
this.f.push(parent+"."+child.uid)
Comment thread
cs-raj marked this conversation as resolved.
Outdated
}

if (!fixTypes.includes(child.data_type) && child.data_type !== 'json') continue;

switch (child.data_type) {
Expand Down Expand Up @@ -317,7 +321,7 @@ export default class ContentType {
return void 0;
}

await this.lookForReference(tree, field);
await this.lookForReference(tree, field, field.uid);
}

/**
Expand Down Expand Up @@ -351,7 +355,7 @@ export default class ContentType {
for (const block of blocks) {
const { uid, title } = block;

await this.lookForReference([...tree, { uid, name: title }], block);
await this.lookForReference([...tree, { uid, name: title }], block, block.uid);
}
}

Expand All @@ -367,7 +371,7 @@ export default class ContentType {
*/
async validateGroupField(tree: Record<string, unknown>[], field: GroupFieldDataType): Promise<void> {
// NOTE Any Group Field related logic can be added here (Ex data serialization or picking any metadata for report etc.,)
await this.lookForReference(tree, field);
await this.lookForReference(tree, field, field.uid);
}

/**
Expand Down
20 changes: 14 additions & 6 deletions packages/contentstack-audit/src/modules/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export default class Entries {
const { uid, title } = entry;
this.currentUid = uid;
this.currentTitle = title;
this.currentTitle = this.removeEmojiAndImages(this.currentTitle)

if (!this.missingRefs[this.currentUid]) {
this.missingRefs[this.currentUid] = [];
Expand All @@ -131,7 +132,7 @@ export default class Entries {
this.removeMissingKeysOnEntry(ctSchema.schema as ContentTypeSchemaType[], this.entries[entryUid]);
}

this.lookForReference([{ locale: code, uid, name: title }], ctSchema, this.entries[entryUid]);
this.lookForReference([{ locale: code, uid, name: this.removeEmojiAndImages(title) }], ctSchema, this.entries[entryUid]);

if (this.missingRefs[this.currentUid]?.length) {
this.missingRefs[this.currentUid].forEach((entry: any) => {
Expand Down Expand Up @@ -650,8 +651,8 @@ export default class Entries {
if (!uid && reference.startsWith('blt')) {
const refExist = find(this.entryMetaData, { uid: reference });
if (!refExist) {
if(Array.isArray(reference_to) && reference_to.length===1) {
missingRefs.push({uid:reference, _content_type_uid: reference_to[0]});
if (Array.isArray(reference_to) && reference_to.length === 1) {
missingRefs.push({ uid: reference, _content_type_uid: reference_to[0] });
} else {
missingRefs.push(reference);
}
Expand Down Expand Up @@ -799,6 +800,13 @@ export default class Entries {
* @returns if there is missing field returns field and path
* Else empty array
*/
removeEmojiAndImages(str: string) {
return str.replace(
Comment thread
cs-raj marked this conversation as resolved.
/[\p{Emoji}\p{Emoji_Presentation}\p{Emoji_Modifier}\p{Emoji_Modifier_Base}\p{Emoji_Component}]+/gu,
'',
);
}

validateSelectField(tree: Record<string, unknown>[], fieldStructure: SelectFeildStruct, field: any) {
const { display_name, enum: selectOptions, multiple, min_instance, display_type, data_type } = fieldStructure;
if (
Expand Down Expand Up @@ -1225,8 +1233,8 @@ export default class Entries {
if (!uid && reference.startsWith('blt')) {
const refExist = find(this.entryMetaData, { uid: reference });
if (!refExist) {
if(Array.isArray(reference_to) && reference_to.length===1) {
missingRefs.push({uid:reference, _content_type_uid: reference_to[0]});
if (Array.isArray(reference_to) && reference_to.length === 1) {
missingRefs.push({ uid: reference, _content_type_uid: reference_to[0] });
} else {
missingRefs.push(reference);
}
Expand Down Expand Up @@ -1399,7 +1407,7 @@ export default class Entries {
`error`,
);
}
this.entryMetaData.push({ uid: entryUid, title, ctUid:uid });
this.entryMetaData.push({ uid: entryUid, title, ctUid: uid });
}
}
}
Expand Down
Loading
Loading