Skip to content

Commit 8f8e3a3

Browse files
Merge pull request #744 from contentstack/dev
Audit and Execution log bug fixes
2 parents 95a8810 + 5f7fbe3 commit 8f8e3a3

File tree

17 files changed

+432
-71
lines changed

17 files changed

+432
-71
lines changed

.talismanrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ fileignoreconfig:
6868

6969
- filename: upload-api/src/config/index.ts
7070
checksum: bd1465785804b3e3942d79f4424498bec838e5aba431c715eb419f3d39cf8d30
71+
- filename: ui/src/components/ContentMapper/index.tsx
72+
checksum: 376fc21e84880c760fab7af4b1bb653f526548f962126c1db7551d036eab765d
73+
- filename: api/src/services/taxonomy.service.ts
74+
checksum: bd2344e7277b41c7eb29c50504c88debf9a86d198c2508dea90d9a98f53d89e9
7175

7276

7377

api/src/constants/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ export const MIGRATION_DATA_CONFIG = {
230230
EXTENSION_APPS_FILE_NAME: "extensions.json",
231231
REFERENCES_DIR_NAME: "reference",
232232
REFERENCES_FILE_NAME: "reference.json",
233+
TAXONOMIES_DIR_NAME: "taxonomies",
234+
TAXONOMIES_FILE_NAME: "taxonomies.json",
233235

234236
RTE_REFERENCES_DIR_NAME: "rteReference",
235237
RTE_REFERENCES_FILE_NAME: "rteReference.json",

api/src/services/migration.service.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { marketPlaceAppService } from './marketplace.service.js';
3232
import { extensionService } from './extension.service.js';
3333
import fsPromises from 'fs/promises';
3434
import { matchesSearchText } from '../utils/search.util.js';
35+
import { taxonomyService } from './taxonomy.service.js';
3536
// import { getSafePath } from "../utils/sanitize-path.utils.js";
3637

3738
/**
@@ -324,6 +325,14 @@ const startTestMigration = async (req: Request): Promise<any> => {
324325
await extensionService?.createExtension({
325326
destinationStackId: project?.current_test_stack_id,
326327
});
328+
await taxonomyService?.createTaxonomy({
329+
orgId,
330+
projectId,
331+
stackId:project?.destination_stack_id,
332+
current_test_stack_id: project?.current_test_stack_id,
333+
region,
334+
userId: user_id,})
335+
327336
switch (cms) {
328337
case CMS.SITECORE_V8:
329338
case CMS.SITECORE_V9:
@@ -901,14 +910,6 @@ const getLogs = async (req: Request): Promise<any> => {
901910
const filterOptions = Array?.from(new Set(logEntries?.map((log) => log?.level)));
902911
const auditStartIndex = logEntries?.findIndex?.(log => log?.message?.includes("Starting audit process"));
903912
const auditEndIndex = logEntries?.findIndex?.(log => log?.message?.includes("Audit process completed"));
904-
if (auditStartIndex === -1 || auditEndIndex === -1) {
905-
logger.warn("Audit markers not found in logs. Skipping audit-related slicing.");
906-
} else {
907-
logEntries = [
908-
...logEntries.slice(0, auditStartIndex),
909-
...logEntries.slice(auditEndIndex + 1)
910-
];
911-
}
912913
logEntries = logEntries?.slice?.(1, logEntries?.length - 2);
913914
if (filter !== "all") {
914915
const filters = filter?.split("-") ?? [];
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
import { getLogMessage, safePromise } from "../utils/index.js";
2+
import getAuthtoken from "../utils/auth.utils.js";
3+
import { config } from "../config/index.js";
4+
import https from "../utils/https.utils.js";
5+
import fs from 'fs';
6+
import { HTTP_TEXTS, MIGRATION_DATA_CONFIG } from "../constants/index.js";
7+
import path from "path";
8+
import logger from "../utils/logger.js";
9+
10+
const {
11+
TAXONOMIES_DIR_NAME,
12+
TAXONOMIES_FILE_NAME
13+
} = MIGRATION_DATA_CONFIG;
14+
15+
const getDescendantsTerm = async ( {authtoken,taxonomyUid, termUid, region, stackId}:
16+
{authtoken: string,taxonomyUid : string, termUid: string, region : string, stackId : string}) => {
17+
const srcFun = "getDescendantsTerm";
18+
19+
try {
20+
const [err, res] = await safePromise(
21+
https({
22+
method: "GET",
23+
url: `${config.CS_API[
24+
region as keyof typeof config.CS_API
25+
]!}/taxonomies/${taxonomyUid}/terms/${termUid}/descendants?include_children_count=true&include_count=true&include_order=true`,
26+
headers: {
27+
api_key : stackId,
28+
authtoken,
29+
},
30+
}));
31+
if (err) {
32+
logger.error(
33+
getLogMessage(srcFun, HTTP_TEXTS.CS_ERROR, {}, err?.response?.data)
34+
);
35+
36+
return {
37+
data: err?.response?.data,
38+
status: err?.response?.status,
39+
};
40+
}
41+
const terms = res?.data?.terms || [];
42+
const allTerms: { uid: string; name: string; parent_uid: string }[] = [];
43+
for (const term of terms) {
44+
// Push current term
45+
allTerms.push({
46+
uid: term?.uid,
47+
name: term?.name,
48+
parent_uid: term?.parent_uid,
49+
});
50+
51+
// Recursively fetch deeper descendants
52+
if (term?.children_count > 0) {
53+
const nestedTerms = await getDescendantsTerm({
54+
authtoken,
55+
taxonomyUid,
56+
termUid: term?.uid,
57+
region,
58+
stackId,
59+
});
60+
61+
if (Array.isArray(nestedTerms)) {
62+
allTerms.push(...nestedTerms);
63+
}
64+
}
65+
}
66+
return allTerms;
67+
} catch (error) {
68+
logger.error("🚀 ~ getDescendantsTerm ~ error:", error);
69+
throw error;
70+
71+
}
72+
}
73+
74+
const createTerms = async(
75+
{authtoken,taxonomyUid, region, stackId}:
76+
{authtoken: string,taxonomyUid : string, region : string, stackId : string}) => {
77+
const srcFun = "createTerms";
78+
try {
79+
const [err, res] = await safePromise(
80+
https({
81+
method: "GET",
82+
url: `${config.CS_API[
83+
region as keyof typeof config.CS_API
84+
]!}/taxonomies/${taxonomyUid}/terms?include_terms_count=true&include_count=true&include_children_count=true&include_referenced_entries_count=true`,
85+
headers: {
86+
api_key : stackId,
87+
authtoken,
88+
},
89+
}));
90+
const termsData = res?.data?.terms;
91+
const allTerms: any[] = [];
92+
for (const term of termsData || []) {
93+
if (term?.uid) {
94+
allTerms.push({
95+
uid: term?.uid,
96+
name: term?.name,
97+
parent_uid: term?.parent_uid,
98+
});
99+
100+
if (term?.children_count > 0) {
101+
const nestedTerms = await getDescendantsTerm({
102+
authtoken,
103+
taxonomyUid,
104+
termUid: term?.uid,
105+
region,
106+
stackId,
107+
});
108+
109+
if (Array.isArray(nestedTerms)) {
110+
allTerms.push(...nestedTerms);
111+
}
112+
}
113+
}
114+
}
115+
116+
117+
118+
119+
if (err) {
120+
logger.error(
121+
getLogMessage(srcFun, HTTP_TEXTS.CS_ERROR, {}, err?.response?.data)
122+
);
123+
124+
return {
125+
data: err?.response?.data,
126+
status: err?.response?.status,
127+
};
128+
}
129+
return allTerms;
130+
131+
} catch (error) {
132+
logger.error("🚀 ~ createTaxonomy ~ error:", error);
133+
throw error;
134+
135+
}
136+
137+
138+
139+
}
140+
const createTaxonomy = async ({stackId,region,userId,current_test_stack_id} :
141+
{orgId: string, stackId: string, projectId:string,region: string,userId: string,current_test_stack_id:string}) => {
142+
const srcFun = "createTaxonomy";
143+
const taxonomiesPath = path.join(MIGRATION_DATA_CONFIG.DATA, current_test_stack_id, TAXONOMIES_DIR_NAME);
144+
await fs.promises.mkdir(taxonomiesPath, { recursive: true });
145+
try {
146+
const authtoken = await getAuthtoken(
147+
region,
148+
userId
149+
);
150+
const [err, res] = await safePromise(
151+
https({
152+
method: "GET",
153+
url: `${config.CS_API[
154+
region as keyof typeof config.CS_API
155+
]!}/taxonomies?include_terms_count=true&include_count=true`,
156+
headers: {
157+
api_key : stackId,
158+
authtoken,
159+
},
160+
})
161+
);
162+
if (err) {
163+
logger.error(
164+
getLogMessage(srcFun, HTTP_TEXTS.CS_ERROR, {}, err?.response?.data)
165+
);
166+
167+
return {
168+
data: err?.response?.data,
169+
status: err?.response?.status,
170+
};
171+
}
172+
173+
const taxonomiesDataObject: Record<string, any> = {};
174+
if (res?.data?.taxonomies) {
175+
for (const taxonomy of res.data.taxonomies) {
176+
if (taxonomy?.uid) {
177+
taxonomiesDataObject[taxonomy.uid] = {
178+
uid: taxonomy?.uid,
179+
name: taxonomy?.name,
180+
description: taxonomy?.description,
181+
};
182+
const singleTaxonomy: any = {};
183+
singleTaxonomy['taxonomy'] = {
184+
uid: taxonomy?.uid,
185+
name: taxonomy?.name,
186+
description: taxonomy?.description,
187+
};
188+
singleTaxonomy['terms'] = await createTerms({ authtoken, taxonomyUid: taxonomy?.uid, region, stackId });
189+
await fs.promises.writeFile(path.join(taxonomiesPath, `${taxonomy?.uid}.json`), JSON.stringify(singleTaxonomy, null, 2));
190+
}
191+
}
192+
}
193+
194+
const filePath = path.join(taxonomiesPath, TAXONOMIES_FILE_NAME);
195+
await fs.promises.writeFile(filePath, JSON.stringify(taxonomiesDataObject, null, 2));
196+
197+
198+
199+
} catch (error) {
200+
logger.error("🚀 ~ createTaxonomy ~ error:", error);
201+
throw error;
202+
}
203+
204+
}
205+
206+
207+
export const taxonomyService = {
208+
createTaxonomy
209+
}
210+

api/src/utils/content-type-creator.utils.ts

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,19 @@ const arrangGroups = ({ schema, newStack }: any) => {
7474
schema?.forEach((item: any) => {
7575
if (item?.contentstackFieldType === 'group') {
7676
const groupSchema: any = { ...item, schema: [] }
77+
if (item?.contentstackFieldUid?.includes('.')) {
78+
const parts = item?.contentstackFieldUid?.split('.');
79+
groupSchema.contentstackFieldUid = parts?.[parts?.length - 1];
80+
}
7781
schema?.forEach((et: any) => {
7882
if (et?.contentstackFieldUid?.includes(`${item?.contentstackFieldUid}.`) ||
7983
(newStack === false && et?.uid?.includes(`${item?.uid}.`))) {
84+
const target = groupSchema?.contentstackFieldUid;
85+
const index = et?.contentstackFieldUid?.indexOf(target);
86+
87+
if (index > 0) {
88+
et.contentstackFieldUid = et?.contentstackFieldUid?.substring?.(index);
89+
}
8090
groupSchema?.schema?.push(et);
8191
}
8292
})
@@ -665,35 +675,51 @@ const mergeArrays = async (a: any[], b: any[]) => {
665675
}
666676
}
667677
return a;
668-
}
678+
};
679+
680+
// Recursive search to find a group by uid anywhere in the schema
681+
const findGroupByUid = (schema: any[], uid: string): any | null => {
682+
for (const field of schema) {
683+
if (field?.data_type === 'group') {
684+
if (field?.uid === uid) return field;
685+
const nested = findGroupByUid(field?.schema ?? [], uid);
686+
if (nested) return nested;
687+
}
688+
}
689+
return null;
690+
};
669691

670692
const mergeTwoCts = async (ct: any, mergeCts: any) => {
671693
const ctData: any = {
672694
...ct,
673695
title: mergeCts?.title,
674696
uid: mergeCts?.uid,
675697
options: {
676-
"singleton": false,
698+
singleton: false,
677699
}
678-
}
679-
for await (const field of ctData?.schema ?? []) {
680-
if (field?.data_type === 'group') {
681-
const currentGroup = mergeCts?.schema?.find((grp: any) => grp?.uid === field?.uid &&
682-
grp?.data_type === 'group');
683-
const group = [];
684-
for await (const fieldGp of currentGroup?.schema ?? []) {
685-
const fieldNst = field?.schema?.find((fld: any) => fld?.uid === fieldGp?.uid &&
686-
fld?.data_type === fieldGp?.data_type);
687-
if (fieldNst === undefined) {
688-
group?.push(fieldGp);
700+
};
701+
702+
const mergeGroupSchema = async (targetSchema: any[], sourceSchema: any[]) => {
703+
for await (const targetField of targetSchema) {
704+
if (targetField?.data_type === 'group') {
705+
const matchingSourceGroup = findGroupByUid(sourceSchema, targetField?.uid);
706+
if (matchingSourceGroup) {
707+
if (!Array.isArray(targetField?.schema)) targetField.schema = [];
708+
if (!Array.isArray(matchingSourceGroup?.schema)) matchingSourceGroup.schema = [];
709+
710+
await mergeGroupSchema(targetField?.schema, matchingSourceGroup?.schema);
711+
targetField.schema = await mergeArrays(targetField?.schema, matchingSourceGroup?.schema);
689712
}
690713
}
691-
field.schema = [...field?.schema ?? [], ...group];
692714
}
693-
}
694-
ctData.schema = await mergeArrays(ctData?.schema, mergeCts?.schema) ?? [];
715+
};
716+
717+
await mergeGroupSchema(ctData?.schema ?? [], mergeCts?.schema ?? []);
718+
ctData.schema = await mergeArrays(ctData?.schema, mergeCts?.schema ?? []);
719+
695720
return ctData;
696-
}
721+
};
722+
697723

698724
export const contenTypeMaker = async ({ contentType, destinationStackId, projectId, newStack, keyMapper, region, user_id }: any) => {
699725
const marketPlacePath = path.join(process.cwd(), MIGRATION_DATA_CONFIG.DATA, destinationStackId);

ui/src/components/AuditFilterModal/index.scss

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
border-bottom: 1px solid #e5e7eb;
2121
display: flex;
2222
align-items: center;
23-
justify-content: space-between;
23+
justify-content: flex-start;
24+
gap: 12px;
25+
.close-btn {
26+
margin-left: auto;
27+
}
2428
}
2529

2630
.tableFilterModalStories__suggestion-item {
@@ -82,4 +86,4 @@
8286
.text-size {
8387
font-size: $size-font-medium;
8488
line-height: $line-height-reset;
85-
}
89+
}

ui/src/components/AuditFilterModal/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const AuditFilterModal = ({
1717
onApply,
1818
selectedLevels,
1919
setFilterValue,
20-
selectedFileType
20+
selectedFileType,
2121
}: AuditFilterModalProps) => {
2222
const modalRef = useRef<HTMLDivElement>(null);
2323

@@ -71,7 +71,7 @@ const AuditFilterModal = ({
7171
<div className="tableFilterModalStories" ref={modalRef}>
7272
<div className="tableFilterModalStories__header">
7373
<span className="text-size">
74-
{selectedFileType?.includes?.('Entries') ? 'Display Type' : 'Field Type'}
74+
{selectedFileType?.includes?.(auditLogsConstants.filterModal.entries) ? auditLogsConstants.filterModal.displayType : auditLogsConstants.filterModal.selectFieldType}
7575
</span>
7676
<div className="close-btn">
7777
<Icon version="v2" icon="CloseNoborder" size="medium" onClick={closeModal} />

0 commit comments

Comments
 (0)