Skip to content

Commit b928688

Browse files
authored
Merge pull request #61 from contentstack/feature/test-migration
Test-migration API added in API folder
2 parents 7ac651d + 59fbefe commit b928688

File tree

10 files changed

+243
-2
lines changed

10 files changed

+243
-2
lines changed

api/src/config/dev.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,11 @@ export const devConfig = {
44
EU: "https://stag-eu-api.csnonprod.com/v3",
55
AZURE_NA: "https://stag-azure-na-api.csnonprod.com/v3",
66
},
7+
CS_URL: {
8+
NA: "https://app.contentstack.com/#!",
9+
EU: "https://eu-app.contentstack.com/#!",
10+
AZURE_NA: "https://azure-na-app.contentstack.com/#!",
11+
AZURE_EU: "https://azure-eu-app.contentstack.com/#!",
12+
}
13+
714
};

api/src/config/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ export type ConfigType = {
2020
AZURE_NA: string;
2121
AZURE_EU?: string;
2222
};
23+
CS_URL: {
24+
NA: string;
25+
EU: string;
26+
AZURE_NA: string;
27+
AZURE_EU?: string;
28+
};
2329
};
2430

2531
export const config: ConfigType = {

api/src/config/prod.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,11 @@ export const prodConfig = {
55
AZURE_NA: "https://azure-na-api.contentstack.com/v3",
66
AZURE_EU: "https://azure-eu-api.contentstack.com/v3",
77
},
8+
CS_URL: {
9+
NA: "https://app.contentstack.com/#!",
10+
EU: "https://eu-app.contentstack.com/#!",
11+
AZURE_NA: "https://azure-na-app.contentstack.com/#!",
12+
AZURE_EU: "https://azure-eu-app.contentstack.com/#!",
13+
}
14+
815
};

api/src/constants/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ export const STEPPER_STEPS = {
111111
LEGACY_CMS: 1,
112112
DESTINATION_STACK: 2,
113113
CONTENT_MAPPING: 3,
114-
MIGRATION: 4,
114+
TESTING : 4,
115+
MIGRATION: 5,
115116
};
116117
export const PREDEFINED_STATUS = [
117118
"Draft",
@@ -120,4 +121,4 @@ export const PREDEFINED_STATUS = [
120121
"Failed",
121122
"Success",
122123
];
123-
export const PREDEFINED_STEPS = [1, 2, 3, 4];
124+
export const PREDEFINED_STEPS = [1, 2, 3, 4,5];
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Request, Response } from "express";
2+
import { migrationService } from "../services/migration.service.js";
3+
4+
const createTestStack = async (req: Request, res: Response): Promise<void> => {
5+
const resp = await migrationService.createTestStack(req);
6+
res.status(200).json(resp);
7+
};
8+
9+
const deleteTestStack = async (req: Request, res: Response): Promise<void> => {
10+
const resp = await migrationService.deleteTestStack(req);
11+
res.status(200).json(resp);
12+
};
13+
14+
15+
export const migrationController = {
16+
createTestStack,
17+
deleteTestStack
18+
};

api/src/models/project-lowdb.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ interface Project {
3434
status: string;
3535
current_step: number;
3636
destination_stack_id: string;
37+
test_stacks: []
38+
current_test_stack_id:string;
3739
legacy_cms: LegacyCMS;
3840
content_mapper: [];
3941
execution_log: [ExecutionLog];

api/src/routes/migration.routes.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import express from "express";
2+
3+
import { asyncRouter } from "../utils/async-router.utils.js";
4+
import { migrationController } from "../controllers/migration.controller.js";
5+
6+
const router = express.Router({ mergeParams: true });
7+
// Create a new project route
8+
router.post(
9+
"/test-stack/:orgId/:projectId",
10+
asyncRouter(migrationController.createTestStack)
11+
);
12+
router.post(
13+
"/test-stack/:projectId",
14+
asyncRouter(migrationController.deleteTestStack)
15+
);
16+
export default router;

api/src/server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { requestHeadersMiddleware } from "./middlewares/req-headers.middleware.j
1515
import { unmatchedRoutesMiddleware } from "./middlewares/unmatched-routes.middleware.js";
1616
import logger from "./utils/logger.js";
1717
import contentMapperRoutes from "./routes/contentMapper.routes.js";
18+
import migrationRoutes from "./routes/migration.routes.js";
1819

1920
try {
2021
const app = express();
@@ -36,6 +37,7 @@ try {
3637
app.use("/v2/org/:orgId", authenticateUser, orgRoutes);
3738
app.use("/v2/org/:orgId/project", authenticateUser, projectRoutes);
3839
app.use("/v2/mapper", authenticateUser, contentMapperRoutes);
40+
app.use("/v2/migration", authenticateUser, migrationRoutes);
3941

4042
//For unmatched route patterns
4143
app.use(unmatchedRoutesMiddleware);
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import { Request } from "express";
2+
import { config } from "../config/index.js";
3+
import { safePromise, getLogMessage } from "../utils/index.js";
4+
import https from "../utils/https.utils.js";
5+
import { LoginServiceType } from "../models/types.js";
6+
import getAuthtoken from "../utils/auth.utils.js";
7+
import logger from "../utils/logger.js";
8+
import { HTTP_TEXTS, HTTP_CODES } from "../constants/index.js";
9+
import { ExceptionFunction } from "../utils/custom-errors.utils.js";
10+
import ProjectModelLowdb from "../models/project-lowdb.js";
11+
12+
const createTestStack = async (req: Request): Promise<LoginServiceType> => {
13+
const srcFun = "createTestStack";
14+
const orgId = req?.params?.orgId;
15+
const projectId = req?.params?.projectId;
16+
const { token_payload, name, description, master_locale } = req.body;
17+
18+
try {
19+
const authtoken = await getAuthtoken(
20+
token_payload?.region,
21+
token_payload?.user_id
22+
);
23+
24+
await ProjectModelLowdb.read();
25+
const projectData = ProjectModelLowdb.chain.get("projects").value();
26+
const testStackCount = projectData[0].test_stacks.length + 1;
27+
const newName = name + "-" + testStackCount;
28+
29+
const [err, res] = await safePromise(
30+
https({
31+
method: "POST",
32+
url: `${config.CS_API[
33+
token_payload?.region as keyof typeof config.CS_API
34+
]!}/stacks`,
35+
headers: {
36+
organization_uid: orgId,
37+
authtoken,
38+
},
39+
data: {
40+
stack: {
41+
name: newName,
42+
description,
43+
master_locale,
44+
},
45+
},
46+
})
47+
);
48+
49+
if (err) {
50+
logger.error(
51+
getLogMessage(
52+
srcFun,
53+
HTTP_TEXTS.CS_ERROR,
54+
token_payload,
55+
err.response.data
56+
)
57+
);
58+
59+
return {
60+
data: err.response.data,
61+
status: err.response.status,
62+
};
63+
}
64+
65+
const index = ProjectModelLowdb.chain
66+
.get("projects")
67+
.findIndex({ id: projectId })
68+
.value();
69+
console.log(index);
70+
if (index > -1) {
71+
ProjectModelLowdb.update((data: any) => {
72+
data.projects[index].current_test_stack_id = res.data.stack.uid;
73+
data.projects[index].test_stacks.push(res.data.stack.uid);
74+
});
75+
}
76+
return {
77+
data: {
78+
data: res.data,
79+
url: `${
80+
config.CS_URL[token_payload?.region as keyof typeof config.CS_URL]
81+
}/stack/${res.data.stack.api_key}/dashboard`,
82+
},
83+
status: res.status,
84+
};
85+
} catch (error: any) {
86+
logger.error(
87+
getLogMessage(
88+
srcFun,
89+
"Error while creating a stack",
90+
token_payload,
91+
error
92+
)
93+
);
94+
95+
throw new ExceptionFunction(
96+
error?.message || HTTP_TEXTS.INTERNAL_ERROR,
97+
error?.statusCode || error?.status || HTTP_CODES.SERVER_ERROR
98+
);
99+
}
100+
};
101+
102+
const deleteTestStack = async (req: Request): Promise<LoginServiceType> => {
103+
const srcFun = "deleteTestStack";
104+
const projectId = req?.params?.projectId;
105+
const { token_payload, stack_key } = req.body;
106+
107+
try {
108+
const authtoken = await getAuthtoken(
109+
token_payload?.region,
110+
token_payload?.user_id
111+
);
112+
113+
const [err, res] = await safePromise(
114+
https({
115+
method: "DELETE",
116+
url: `${config.CS_API[
117+
token_payload?.region as keyof typeof config.CS_API
118+
]!}/stacks`,
119+
headers: {
120+
api_key: stack_key,
121+
authtoken,
122+
},
123+
})
124+
);
125+
126+
if (err) {
127+
logger.error(
128+
getLogMessage(
129+
srcFun,
130+
HTTP_TEXTS.CS_ERROR,
131+
token_payload,
132+
err.response.data
133+
)
134+
);
135+
136+
return {
137+
data: err.response.data,
138+
status: err.response.status,
139+
};
140+
}
141+
142+
const index = ProjectModelLowdb.chain
143+
.get("projects")
144+
.findIndex({ id: projectId })
145+
.value();
146+
console.log(index);
147+
if (index > -1) {
148+
ProjectModelLowdb.update((data: any) => {
149+
data.projects[index].current_test_stack_id = "";
150+
const stackIndex = data.projects[index].test_stacks.indexOf(stack_key);
151+
if (stackIndex > -1) {
152+
data.projects[index].test_stacks.splice(stackIndex, 1);
153+
}
154+
});
155+
}
156+
return {
157+
data: res.data,
158+
status: res.status,
159+
};
160+
} catch (error: any) {
161+
logger.error(
162+
getLogMessage(
163+
srcFun,
164+
"Error while creating a stack",
165+
token_payload,
166+
error
167+
)
168+
);
169+
170+
throw new ExceptionFunction(
171+
error?.message || HTTP_TEXTS.INTERNAL_ERROR,
172+
error?.statusCode || error?.status || HTTP_CODES.SERVER_ERROR
173+
);
174+
}
175+
};
176+
177+
export const migrationService = {
178+
createTestStack,
179+
deleteTestStack,
180+
};

api/src/services/projects.service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ const createProject = async (req: Request) => {
7777
status: PROJECT_STATUS.DRAFT,
7878
current_step: STEPPER_STEPS.LEGACY_CMS,
7979
destination_stack_id: "",
80+
test_stacks: [],
81+
current_test_stack_id: "",
8082
legacy_cms: {},
8183
content_mapper: [],
8284
execution_log: [],

0 commit comments

Comments
 (0)