Skip to content

Commit 3c16405

Browse files
authored
Merge pull request #515 from contentstack/dev
Dev
2 parents 6664804 + ac033b6 commit 3c16405

File tree

36 files changed

+2118
-157
lines changed

36 files changed

+2118
-157
lines changed

.DS_Store

-6 KB
Binary file not shown.

.github/workflows/repo-sync.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ jobs:
118118
env:
119119
GH_TOKEN: ${{ secrets.GH_PAT }}
120120

121-
- name: Sync changes to wordpress-repo (if applicable)
121+
- name: Sync changes to contentful-repo (if applicable)
122122
if: |
123123
env.merged == 'true' &&
124124
(

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ MigrationBackup/
349349
# Ionide (cross platform F# VS Code tools) working folder
350350
.ionide/
351351

352+
**.DS_Store
352353

353354
upload-api/node_modules
354355
upload-api/build

api/.DS_Store

-6 KB
Binary file not shown.

api/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dist/
1717
# Mono auto generated files
1818
mono_crash.*
1919

20+
2021
# Build results
2122
[Dd]ebug/
2223
[Dd]ebugPublic/
@@ -358,6 +359,7 @@ combine.log
358359

359360

360361
!example.env
362+
!production.env
361363

362364
database/
363365
/sitecoreMigrationData

api/src/.DS_Store

-8 KB
Binary file not shown.

api/src/controllers/migration.controller.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Request, Response } from "express";
2-
import { migrationService } from "../services/migration.service.js";
2+
import { migrationService } from "../services/migration.service.js"
33

44
/**
55
* Creates a test stack.
@@ -55,10 +55,22 @@ const getLogs = async (req: Request, res: Response): Promise<void> => {
5555
res.status(200).json(resp);
5656
};
5757

58+
const saveLocales = async (req:Request, res: Response):Promise<void> =>{
59+
const resp = await migrationService.createSourceLocales(req)
60+
res.status(200).json(resp);
61+
}
62+
63+
const saveMappedLocales = async (req:Request, res:Response):Promise<void> =>{
64+
const resp = await migrationService.updateLocaleMapper(req);
65+
res.status(200).json(resp);
66+
}
67+
5868
export const migrationController = {
5969
createTestStack,
6070
deleteTestStack,
6171
startTestMigration,
6272
startMigration,
6373
getLogs,
74+
saveLocales,
75+
saveMappedLocales
6476
};

api/src/routes/migration.routes.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,31 @@ router.get(
6565

6666
)
6767

68+
/**
69+
* Route for updating the source locales from legacy CMS
70+
* @route POST /validator
71+
* @group Migration
72+
* @param {string} projectID - Current project ID
73+
* @body {Object} locales - Fetched Locales
74+
* @returns {Promise<void>} - A promise which resolves when the locales are updated in the DB
75+
*/
76+
router.post(
77+
"/localeMapper/:projectId",
78+
asyncRouter(migrationController.saveLocales)
79+
)
80+
81+
/**
82+
* Route for updating the mapped locales by user
83+
* @route POST /validator
84+
* @group Migration
85+
* @param {string} projectID - Current project ID
86+
* @body {Object} locales - Mapped Locales
87+
* @returns {Promise<void>} - A promise which resolves when the locales are updated in the DB
88+
*/
89+
router.post(
90+
"/updateLocales/:projectId",
91+
asyncRouter(migrationController.saveMappedLocales)
92+
)
93+
6894

6995
export default router;

api/src/services/contentful.service.ts

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -88,39 +88,44 @@ function makeChunks(assetData: any) {
8888

8989
const transformCloudinaryObject = (input: any) => {
9090
const result: any = [];
91+
if (!Array.isArray(input)) {
92+
return result;
93+
}
9194
for (const metaData of input ?? []) {
92-
result?.push({
93-
public_id: metaData.public_id,
94-
resource_type: metaData.resource_type,
95-
type: metaData.type,
96-
format: metaData.format,
97-
version: metaData.version,
98-
url: metaData.original_url,
99-
secure_url: metaData.original_secure_url,
100-
width: metaData.width,
101-
height: metaData.height,
102-
bytes: metaData.bytes,
103-
duration: metaData.duration,
104-
tags: metaData.tags,
105-
metadata: metaData.metadata,
106-
created_at: metaData.created_at,
107-
access_mode: "public",
108-
access_control: [],
109-
created_by: {
110-
type: "",
111-
id: ""
112-
},
113-
uploaded_by: {
114-
type: "",
115-
id: ""
116-
},
117-
folder_id: "",
118-
id: "",
119-
folder: "",
120-
cs_metadata: {
121-
config_label: "config"
122-
}
123-
});
95+
if (metaData?.public_id) {
96+
result?.push({
97+
public_id: metaData?.public_id,
98+
resource_type: metaData?.resource_type,
99+
type: metaData?.type,
100+
format: metaData?.format,
101+
version: metaData?.version,
102+
url: metaData?.original_url,
103+
secure_url: metaData?.original_secure_url,
104+
width: metaData?.width,
105+
height: metaData?.height,
106+
bytes: metaData?.bytes,
107+
duration: metaData?.duration,
108+
tags: metaData?.tags,
109+
metadata: metaData?.metadata,
110+
created_at: metaData?.created_at,
111+
access_mode: "public",
112+
access_control: [],
113+
created_by: {
114+
type: "",
115+
id: ""
116+
},
117+
uploaded_by: {
118+
type: "",
119+
id: ""
120+
},
121+
folder_id: uuidv4(),
122+
id: uuidv4(),
123+
folder: "",
124+
cs_metadata: {
125+
config_label: "config"
126+
}
127+
});
128+
}
124129
}
125130
return result;
126131
}
@@ -185,7 +190,7 @@ function convertToArray(data: any) {
185190
if (typeof data === 'object' && data !== null && !Array.isArray(data)) {
186191
return [data]// Converts object values into an array
187192
}
188-
return data; // Return as is if it's already an array or not an object
193+
return data ?? []; // Return as is if it's already an array or not an object
189194
}
190195

191196
const mktApp = (type: string, data: any) => {
@@ -736,7 +741,6 @@ const mapLocales = ({ masterLocale, locale, locales }: any) => {
736741
* @throws Will log errors encountered during file reading, processing, or writing of entries.
737742
*/
738743
const createEntry = async (packagePath: any, destination_stack_id: string, projectId: string, contentTypes: any, mapperKeys: any, master_locale: string): Promise<void> => {
739-
console.info("🚀 ~ createEntry ~ master_locale:", master_locale)
740744
const srcFunc = 'createEntry';
741745
try {
742746
const entriesSave = path.join(DATA, destination_stack_id, ENTRIES_DIR_NAME);
@@ -783,7 +787,7 @@ const createEntry = async (packagePath: any, destination_stack_id: string, proje
783787
entryData[name][lang][id] ??= {};
784788
locales.push(lang);
785789
const fieldData = currentCT?.fieldMapping?.find((item: any) => key === item?.uid);
786-
const newId = fieldData?.contentstackFieldUid ?? `${key}`.replace(/[^a-zA-Z0-9]+/g, "_");
790+
const newId = fieldData?.contentstackFieldUid ?? `${key}`?.replace?.(/[^a-zA-Z0-9]+/g, "_");
787791
entryData[name][lang][id][newId] = processField(
788792
langValue,
789793
entryId,
@@ -796,16 +800,14 @@ const createEntry = async (packagePath: any, destination_stack_id: string, proje
796800
const pathName = getDisplayName(name, displayField);
797801
locales.forEach((locale) => {
798802
const localeCode = mapLocales({ masterLocale: master_locale, locale, locales: LOCALE_MAPPER });
799-
console.info("🚀 ~ locales.forEach ~ localeCode:", localeCode);
800803
const publishDetails = Object?.values?.(environmentsId)?.length ? Object?.values?.(environmentsId)
801804
.filter((env: any) => env?.name === environment_id)
802805
?.map((env: any) => ({
803806
environment: env?.uid,
804807
version: 1,
805-
locale: locale?.toLowerCase(),
808+
locale: locale?.toLowerCase?.(),
806809
})) : [];
807-
808-
const title = entryData[name][locale][id][pathName] || "";
810+
const title = fields?.[pathName]?.[locale] || "";
809811
const urlTitle = title
810812
?.replace?.(/[^a-zA-Z0-9]+/g, "-")
811813
?.toLowerCase?.();
@@ -858,7 +860,7 @@ const createEntry = async (packagePath: any, destination_stack_id: string, proje
858860
);
859861
for await (const [chunkId, chunkData] of Object.entries(chunks)) {
860862
refs[chunkIndex++] = `${chunkId}-entries.json`;
861-
await writeFile(filePath, `${chunkId}-entries.json`, chunkData)
863+
await writeFile(filePath, `${chunkId}-entries.json`, chunkData);
862864
}
863865
await writeFile(filePath, ENTRIES_MASTER_FILE, refs);
864866
}

api/src/services/migration.service.ts

Lines changed: 109 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import { extensionService } from "./extension.service.js";
2525

2626

2727

28-
2928
/**
3029
* Creates a test stack.
3130
*
@@ -245,10 +244,10 @@ const startTestMigration = async (req: Request): Promise<any> => {
245244
await wordpressService?.extractChunks(file_path, packagePath, project?.current_test_stack_id, projectId)
246245
await wordpressService?.getAllAuthors(file_path, packagePath, project?.current_test_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
247246
//await wordpressService?.extractContentTypes(projectId, project?.current_test_stack_id, contentTypes)
248-
await wordpressService?.getAllTerms(file_path, packagePath, project?.current_test_stack_id, projectId, contentTypes, project?.mapperKeys,project?.stackDetails?.master_locale)
249-
await wordpressService?.getAllTags(file_path, packagePath, project?.current_test_stack_id, projectId, contentTypes, project?.mapperKeys,project?.stackDetails?.master_locale)
250-
await wordpressService?.getAllCategories(file_path, packagePath, project?.current_test_stack_id, projectId, contentTypes, project?.mapperKeys,project?.stackDetails?.master_locale)
251-
await wordpressService?.extractPosts(packagePath, project?.current_test_stack_id, projectId, contentTypes, project?.mapperKeys,project?.stackDetails?.master_locale)
247+
await wordpressService?.getAllTerms(file_path, packagePath, project?.current_test_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
248+
await wordpressService?.getAllTags(file_path, packagePath, project?.current_test_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
249+
await wordpressService?.getAllCategories(file_path, packagePath, project?.current_test_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
250+
await wordpressService?.extractPosts(packagePath, project?.current_test_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
252251
await wordpressService?.extractGlobalFields(project?.current_test_stack_id, projectId)
253252
await wordpressService?.createVersionFile(project?.current_test_stack_id, projectId);
254253
}
@@ -319,12 +318,12 @@ const startMigration = async (req: Request): Promise<any> => {
319318
await wordpressService?.createAssetFolderFile(file_path, project?.destination_stack_id, projectId)
320319
await wordpressService?.getAllreference(file_path, packagePath, project?.destination_stack_id, projectId)
321320
await wordpressService?.extractChunks(file_path, packagePath, project?.destination_stack_id, projectId)
322-
await wordpressService?.getAllAuthors(file_path, packagePath, project?.destination_stack_id, projectId, contentTypes, project?.mapperKeys,project?.stackDetails?.master_locale)
321+
await wordpressService?.getAllAuthors(file_path, packagePath, project?.destination_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
323322
//await wordpressService?.extractContentTypes(projectId, project?.destination_stack_id)
324323
await wordpressService?.getAllTerms(file_path, packagePath, project?.destination_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
325-
await wordpressService?.getAllTags(file_path, packagePath, project?.destination_stack_id, projectId, contentTypes, project?.mapperKeys,project?.stackDetails?.master_locale)
326-
await wordpressService?.getAllCategories(file_path, packagePath, project?.destination_stack_id, projectId, contentTypes, project?.mapperKeys,project?.stackDetails?.master_locale)
327-
await wordpressService?.extractPosts(packagePath, project?.destination_stack_id, projectId, contentTypes, project?.mapperKeys,project?.stackDetails?.master_locale)
324+
await wordpressService?.getAllTags(file_path, packagePath, project?.destination_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
325+
await wordpressService?.getAllCategories(file_path, packagePath, project?.destination_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
326+
await wordpressService?.extractPosts(packagePath, project?.destination_stack_id, projectId, contentTypes, project?.mapperKeys, project?.stackDetails?.master_locale)
328327
await wordpressService?.extractGlobalFields(project?.destination_stack_id, projectId)
329328
await wordpressService?.createVersionFile(project?.destination_stack_id, projectId);
330329

@@ -411,10 +410,111 @@ const getLogs = async (req: Request): Promise<any> => {
411410

412411
}
413412

413+
/**
414+
* @description - This function takes all the fetched locales from the exported data of the legacy CMS and stores/updates them in the project.json in DB
415+
*
416+
* @param req - A request body object with fetched locales [] as payload along with project ID in params
417+
* @return - void
418+
* @throws Exception if the project ID is invalid or the when the path to project.json is incorrect
419+
*/
420+
export const createSourceLocales = async (req: Request) => {
421+
422+
const projectFilePath = path.join(process.cwd(), 'database', 'project.json'); // Adjusted path to project.json
423+
const projectId = req.params.projectId;
424+
425+
const locales = req.body.locale
426+
427+
try {
428+
// Check if the project.json file exists
429+
if (!fs?.existsSync?.(projectFilePath)) {
430+
console.error(`project.json not found at ${projectFilePath}`);
431+
throw new Error(`project.json not found.`);
432+
}
433+
434+
// Find the project with the specified projectId
435+
const project: any = ProjectModelLowdb?.chain?.get?.("projects")?.find?.({ id: projectId })?.value?.();
436+
if (project) {
437+
const index = ProjectModelLowdb?.chain?.get?.("projects")?.findIndex?.({ id: projectId })?.value();
438+
if (index > -1) {
439+
440+
ProjectModelLowdb?.update((data: any) => {
441+
data.projects[index].source_locales = locales;
442+
});
443+
} // Write back the updated projects
444+
} else {
445+
logger.error(`Project with ID: ${projectId} not found`, {
446+
status: HTTP_CODES?.NOT_FOUND,
447+
message: HTTP_TEXTS?.INVALID_ID
448+
})
449+
}
450+
} catch (err: any) {
451+
console.error("🚀 ~ createSourceLocales ~ err:", err?.response?.data ?? err, err)
452+
logger.warn('Bad Request', {
453+
status: HTTP_CODES?.BAD_REQUEST,
454+
message: HTTP_TEXTS?.INTERNAL_ERROR,
455+
});
456+
throw new ExceptionFunction(
457+
err?.message || HTTP_TEXTS.INTERNAL_ERROR,
458+
err?.statusCode || err?.status || HTTP_CODES.SERVER_ERROR
459+
);
460+
}
461+
}
462+
463+
464+
/**
465+
* @description - Function retrieves the mapped locales and updates them in the project.json in DB
466+
* @param req - A request body object with mapped locales as payload and project ID in the params
467+
* @return - void
468+
* @throws Exception if the project ID is invalid or the when the path to project.json is incorrect
469+
*/
470+
export const updateLocaleMapper = async (req: Request) => {
471+
const mapperObject = req?.body;
472+
const projectFilePath = path?.join?.(process?.cwd(), 'database', 'project.json'); // Adjusted path to project.json
473+
const projectId = req?.params?.projectId;
474+
475+
try {
476+
// Check if the project.json file exists
477+
if (!fs?.existsSync?.(projectFilePath)) {
478+
console.error(`project.json not found at ${projectFilePath}`);
479+
throw new Error(`project.json not found.`);
480+
}
481+
482+
// Find the project with the specified projectId
483+
const project: any = ProjectModelLowdb?.chain?.get?.("projects")?.find?.({ id: projectId })?.value();
484+
if (project) {
485+
const index = ProjectModelLowdb?.chain?.get("projects")?.findIndex?.({ id: projectId })?.value();
486+
if (index > -1) {
487+
ProjectModelLowdb?.update((data: any) => {
488+
data.projects[index].master_locale = mapperObject?.master_locale;
489+
data.projects[index].locales = mapperObject?.locales;
490+
});
491+
} // Write back the updated projects
492+
} else {
493+
logger.error(`Project with ID: ${projectId} not found`, {
494+
status: HTTP_CODES?.NOT_FOUND,
495+
message: HTTP_TEXTS?.INVALID_ID
496+
})
497+
}
498+
} catch (err: any) {
499+
console.error("🚀 ~ updateLocaleMapper ~ err:", err?.response?.data ?? err, err)
500+
logger.warn('Bad Request', {
501+
status: HTTP_CODES?.BAD_REQUEST,
502+
message: HTTP_TEXTS?.INTERNAL_ERROR,
503+
});
504+
throw new ExceptionFunction(
505+
err?.message || HTTP_TEXTS.INTERNAL_ERROR,
506+
err?.statusCode || err?.status || HTTP_CODES.SERVER_ERROR
507+
);
508+
}
509+
510+
}
511+
414512
export const migrationService = {
415513
createTestStack,
416514
deleteTestStack,
417515
startTestMigration,
418516
startMigration,
419517
getLogs,
518+
createSourceLocales,
519+
updateLocaleMapper
420520
};

0 commit comments

Comments
 (0)