Skip to content

Commit a8793f8

Browse files
committed
feat: add taxonomy service and resolved bugs
1 parent 74a0db4 commit a8793f8

File tree

10 files changed

+381
-34
lines changed

10 files changed

+381
-34
lines changed

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 & 0 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:
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+
console.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+
console.info("🚀 ~ createTerms ~ nestedTerms:", nestedTerms);
114+
}
115+
}
116+
}
117+
118+
119+
120+
121+
if (err) {
122+
logger.error(
123+
getLogMessage(srcFun, HTTP_TEXTS.CS_ERROR, {}, err?.response?.data)
124+
);
125+
126+
return {
127+
data: err?.response?.data,
128+
status: err?.response?.status,
129+
};
130+
}
131+
return allTerms;
132+
133+
} catch (error) {
134+
console.error("🚀 ~ createTaxonomy ~ error:", error);
135+
throw error;
136+
137+
}
138+
139+
140+
141+
}
142+
const createTaxonomy = async ({stackId,region,userId,current_test_stack_id} :
143+
{orgId: string, stackId: string, projectId:string,region: string,userId: string,current_test_stack_id:string}) => {
144+
const srcFun = "createTaxonomy";
145+
const taxonomiesPath = path.join(MIGRATION_DATA_CONFIG.DATA, current_test_stack_id, TAXONOMIES_DIR_NAME);
146+
await fs.promises.mkdir(taxonomiesPath, { recursive: true });
147+
try {
148+
const authtoken = await getAuthtoken(
149+
region,
150+
userId
151+
);
152+
const [err, res] = await safePromise(
153+
https({
154+
method: "GET",
155+
url: `${config.CS_API[
156+
region as keyof typeof config.CS_API
157+
]!}/taxonomies?include_terms_count=true&include_count=true`,
158+
headers: {
159+
api_key : stackId,
160+
authtoken,
161+
},
162+
})
163+
);
164+
if (err) {
165+
logger.error(
166+
getLogMessage(srcFun, HTTP_TEXTS.CS_ERROR, {}, err?.response?.data)
167+
);
168+
169+
return {
170+
data: err?.response?.data,
171+
status: err?.response?.status,
172+
};
173+
}
174+
175+
const taxonomiesDataObject: Record<string, any> = {};
176+
res?.data?.taxonomies?.forEach(async (taxonomy: any) => {
177+
if (taxonomy?.uid) {
178+
taxonomiesDataObject[taxonomy.uid] = {
179+
uid: taxonomy?.uid,
180+
name: taxonomy?.name,
181+
description: taxonomy?.description,
182+
};
183+
const singleTaxonomy: any= {};
184+
singleTaxonomy['taxonomy']= {
185+
uid: taxonomy?.uid,
186+
name: taxonomy?.name,
187+
description: taxonomy?.description,
188+
}
189+
singleTaxonomy['terms'] = await createTerms({authtoken,taxonomyUid: taxonomy?.uid,region, stackId});
190+
await fs.promises.writeFile(path.join(taxonomiesPath, `${taxonomy?.uid}.json`), JSON.stringify(singleTaxonomy, null, 2));
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+
console.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);

0 commit comments

Comments
 (0)