From c357196080269e138fd1813392f4107e19ffdf4c Mon Sep 17 00:00:00 2001 From: hanoak20 Date: Tue, 23 Jan 2024 23:13:58 +0530 Subject: [PATCH 1/8] fix: removed the TODOs comments. --- src/services/auth.service.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts index ca89ba423..ed250e6cd 100644 --- a/src/services/auth.service.ts +++ b/src/services/auth.service.ts @@ -12,7 +12,6 @@ import { import AuthenticationModel from "../models/authentication"; const login = async (req: Request): Promise => { - //TODO: 1. request validation const userData = req?.body; const [err, res] = await safePromise( @@ -78,7 +77,6 @@ const login = async (req: Request): Promise => { }; const requestSms = async (req: Request): Promise => { - //TODO: 1. request validation const userData = req?.body; try { From ed645f5ef10c711970f27554ae46527f167ec1f0 Mon Sep 17 00:00:00 2001 From: hanoak20 Date: Thu, 25 Jan 2024 13:10:32 +0530 Subject: [PATCH 2/8] chore: Added migration's crud APIs with schema change. --- src/constants/index.ts | 12 ++ .../projects.migrations.controller.ts | 16 +- src/models/project.ts | 36 +++-- src/models/types.ts | 8 + src/services/projects.migrations.service.ts | 138 +++++++++++++++++- src/utils/index.ts | 7 + 6 files changed, 187 insertions(+), 30 deletions(-) diff --git a/src/constants/index.ts b/src/constants/index.ts index 3eabc5098..c0ad1275a 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -37,6 +37,12 @@ export type HttpErrorTexts = { TOKEN_ERROR: string; LOGIN_ERROR: string; ROUTE_ERROR: string; + NO_PROJECT: string; + MIGRATION_CREATED: string; + MIGRATION_UPDATED: string; + MIGRATION_DELETED: string; + INVALID_ID: string; + MIGRATION_EXISTS: string; }; export type HttpResponseHeaders = { @@ -70,6 +76,12 @@ export const constants: ConstantType = { TOKEN_ERROR: "Error occurred during token generation.", LOGIN_ERROR: "Error occurred during login", ROUTE_ERROR: "Sorry, the requested resource is not available.", + NO_PROJECT: "resource not found with the given ID(s).", + MIGRATION_CREATED: "Project's migration created successfully.", + MIGRATION_UPDATED: "Project's migration updated successfully.", + MIGRATION_DELETED: "Project's migration deleted successfully.", + INVALID_ID: "Provided $ ID is invalid.", + MIGRATION_EXISTS: "Project's migration already exists.", }, HTTP_RESPONSE_HEADERS: { "Access-Control-Allow-Origin": "*", diff --git a/src/controllers/projects.migrations.controller.ts b/src/controllers/projects.migrations.controller.ts index 37268820f..b7e775cc1 100644 --- a/src/controllers/projects.migrations.controller.ts +++ b/src/controllers/projects.migrations.controller.ts @@ -1,23 +1,23 @@ import { Request, Response } from "express"; import { migrationService } from "../services/projects.migrations.service"; -const getMigration = async (req: Request, res: Response): Promise => { +const getMigration = async (req: Request, res: Response) => { const resp = await migrationService.getMigration(req); - res.status(200).json(resp); + res.status(resp.status).json(resp.data); }; -const createMigration = async (req: Request, res: Response): Promise => { +const createMigration = async (req: Request, res: Response) => { const resp = await migrationService.createMigration(req); - res.status(201).json(resp); + res.status(resp.status).json(resp.data); }; -const updateMigration = async (req: Request, res: Response): Promise => { +const updateMigration = async (req: Request, res: Response) => { const resp = await migrationService.updateMigration(req); - res.status(200).json(resp); + res.status(resp.status).json(resp.data); }; -const deleteMigration = async (req: Request, res: Response): Promise => { +const deleteMigration = async (req: Request, res: Response) => { const resp = await migrationService.deleteMigration(req); - res.status(200).json(resp); + res.status(resp.status).json(resp.data); }; export const migrationController = { diff --git a/src/models/project.ts b/src/models/project.ts index 60738430e..96a675162 100644 --- a/src/models/project.ts +++ b/src/models/project.ts @@ -18,8 +18,11 @@ interface Modules { } interface Migration { + _id: Schema.Types.ObjectId; name: string; description: string; + created_at: Date; + updated_at: Date; modules: Modules; } @@ -35,7 +38,7 @@ interface ProjectDocument extends Document { name: string; description: string; status: boolean; - migration: Migration; + migration: [Migration]; execution_log: ExecutionLog; } @@ -48,21 +51,26 @@ const projectSchema = new Schema( name: { type: String, required: true }, description: { type: String, required: true }, status: { type: Boolean, default: true }, - migration: { - name: { type: String }, - description: { type: String }, - modules: { - legacy_cms: { - cms: { type: String }, - file_format: { type: String }, - import_data: { type: String }, - }, - destination_cms: { - stack_id: { type: String }, - org_id: { type: String }, + migration: [ + { + _id: Schema.Types.ObjectId, + name: { type: String }, + description: { type: String }, + created_at: { type: Date }, + updated_at: { type: Date }, + modules: { + legacy_cms: { + cms: { type: String }, + file_format: { type: String }, + import_data: { type: String }, + }, + destination_cms: { + stack_id: { type: String }, + org_id: { type: String }, + }, }, }, - }, + ], execution_log: { log_url: { type: String }, }, diff --git a/src/models/types.ts b/src/models/types.ts index 5be9656ee..2dae0ab6a 100644 --- a/src/models/types.ts +++ b/src/models/types.ts @@ -21,3 +21,11 @@ export interface LoginServiceType { data: any; status: number; } + +export interface MigrationQueryType { + _id: string; + "migration._id"?: string; + org_id: string; + region: string; + owner: string; +} diff --git a/src/services/projects.migrations.service.ts b/src/services/projects.migrations.service.ts index 58b19f89b..47bcb5cb1 100644 --- a/src/services/projects.migrations.service.ts +++ b/src/services/projects.migrations.service.ts @@ -1,18 +1,91 @@ +/* eslint-disable operator-linebreak */ import { Request } from "express"; +import { constants } from "../constants"; +import ProjectModel from "../models/project"; +import { isValidObjectId, getMongooseID } from "../utils"; +import { NotFoundError, BadRequestError } from "../utils/custom-errors.utils"; +import { MigrationQueryType } from "../models/types"; + +const _getProject = async (projectId: string, query: MigrationQueryType) => { + if (!isValidObjectId(projectId)) + throw new BadRequestError( + constants.HTTP_TEXTS.INVALID_ID.replace("$", "project") + ); + + const project = await ProjectModel.findOne(query); + + if (!project) throw new NotFoundError(constants.HTTP_TEXTS.NO_PROJECT); + + return project; +}; + +const _getCondensedMigration = (projectId: string, data: any) => { + return { + id: data._id, + name: data.name, + description: data.description, + created_at: data.created_at, + updated_at: data.updated_at, + project_id: projectId, + org_id: data.org_id, + }; +}; const getMigration = async (req: Request) => { const orgId = req?.params?.orgId; const projectId = req?.params?.projectId; - //Add logic to get Project from DB - return { orgId, projectId }; + const project = await _getProject(projectId, { + _id: projectId, + org_id: orgId, + region: req?.body?.token_payload?.region, + owner: req?.body?.token_payload?.user_id, + }); + + return { + status: constants.HTTP_CODES.OK, + data: { + migration: [ + project.migration?.[0]?._id + ? _getCondensedMigration(projectId, project.migration[0]) + : {}, + ], + }, + }; }; + const createMigration = async (req: Request) => { const orgId = req?.params?.orgId; const projectId = req?.params?.projectId; - //Add logic to create Project from DB - return { orgId, projectId }; + const project = await _getProject(projectId, { + _id: projectId, + org_id: orgId, + region: req?.body?.token_payload?.region, + owner: req?.body?.token_payload?.user_id, + }); + + if (project.migration?.length) + throw new BadRequestError(constants.HTTP_TEXTS.MIGRATION_EXISTS); + + project.migration.push({ + _id: getMongooseID(), + created_at: new Date(), + updated_at: new Date(), + ...req?.body, + }); + + const updatedProject = await project.save(); + + return { + status: constants.HTTP_CODES.OK, + data: { + message: constants.HTTP_TEXTS.MIGRATION_CREATED, + migration: [ + _getCondensedMigration(projectId, updatedProject.migration[0]), + ], + }, + }; }; const updateMigration = async (req: Request) => { @@ -20,8 +93,34 @@ const updateMigration = async (req: Request) => { const projectId = req?.params?.projectId; const migrationId = req?.params?.migrationId; - //Add logic to update Project from DB - return { orgId, projectId, migrationId }; + if (!isValidObjectId(migrationId)) + throw new BadRequestError( + constants.HTTP_TEXTS.INVALID_ID.replace("$", "migration") + ); + + const project = await _getProject(projectId, { + _id: projectId, + "migration._id": migrationId, + org_id: orgId, + region: req?.body?.token_payload?.region, + owner: req?.body?.token_payload?.user_id, + }); + + project.migration[0].name = req?.body?.name; + project.migration[0].description = req?.body?.description; + project.migration[0].updated_at = new Date(); + + const updatedProject = await project.save(); + + return { + status: constants.HTTP_CODES.OK, + data: { + message: constants.HTTP_TEXTS.MIGRATION_UPDATED, + migration: [ + _getCondensedMigration(projectId, updatedProject.migration[0]), + ], + }, + }; }; const deleteMigration = async (req: Request) => { @@ -29,8 +128,31 @@ const deleteMigration = async (req: Request) => { const projectId = req?.params?.projectId; const migrationId = req?.params?.migrationId; - //Add logic to delete Project from DB - return { orgId, projectId, migrationId }; + if (!isValidObjectId(migrationId)) + throw new BadRequestError( + constants.HTTP_TEXTS.INVALID_ID.replace("$", "migration") + ); + + const filter = { + _id: projectId, + "migration._id": migrationId, + org_id: orgId, + region: req?.body?.token_payload?.region, + owner: req?.body?.token_payload?.user_id, + }; + + const project = await _getProject(projectId, filter); + + project.migration.shift(); + await project.save(); + + return { + status: constants.HTTP_CODES.OK, + data: { + status: constants.HTTP_CODES.OK, + message: constants.HTTP_TEXTS.MIGRATION_DELETED, + }, + }; }; export const migrationService = { diff --git a/src/utils/index.ts b/src/utils/index.ts index 79662e175..a83fae241 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,3 +1,5 @@ +import mongoose from "mongoose"; + export const throwError = (message: string, statusCode: number) => { throw Object.assign(new Error(message), { statusCode }); }; @@ -19,3 +21,8 @@ export const getLogMessage = (methodName: string, message = {}, user = {}) => { user: user, }; }; + +export const isValidObjectId = (id: string | undefined) => + mongoose.isValidObjectId(id); + +export const getMongooseID = () => new mongoose.Types.ObjectId(); From 0a7bbbe57309b854835abc07c25252bb61f5944f Mon Sep 17 00:00:00 2001 From: hanoak20 Date: Thu, 25 Jan 2024 13:32:59 +0530 Subject: [PATCH 3/8] chore: destructured the req body. --- src/services/projects.migrations.service.ts | 24 ++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/services/projects.migrations.service.ts b/src/services/projects.migrations.service.ts index 47bcb5cb1..291e284ec 100644 --- a/src/services/projects.migrations.service.ts +++ b/src/services/projects.migrations.service.ts @@ -34,12 +34,13 @@ const _getCondensedMigration = (projectId: string, data: any) => { const getMigration = async (req: Request) => { const orgId = req?.params?.orgId; const projectId = req?.params?.projectId; + const { token_payload } = req.body; const project = await _getProject(projectId, { _id: projectId, org_id: orgId, - region: req?.body?.token_payload?.region, - owner: req?.body?.token_payload?.user_id, + region: token_payload?.region, + owner: token_payload?.user_id, }); return { @@ -57,12 +58,13 @@ const getMigration = async (req: Request) => { const createMigration = async (req: Request) => { const orgId = req?.params?.orgId; const projectId = req?.params?.projectId; + const { token_payload } = req.body; const project = await _getProject(projectId, { _id: projectId, org_id: orgId, - region: req?.body?.token_payload?.region, - owner: req?.body?.token_payload?.user_id, + region: token_payload?.region, + owner: token_payload?.user_id, }); if (project.migration?.length) @@ -92,6 +94,7 @@ const updateMigration = async (req: Request) => { const orgId = req?.params?.orgId; const projectId = req?.params?.projectId; const migrationId = req?.params?.migrationId; + const { token_payload, name, description } = req.body; if (!isValidObjectId(migrationId)) throw new BadRequestError( @@ -102,12 +105,12 @@ const updateMigration = async (req: Request) => { _id: projectId, "migration._id": migrationId, org_id: orgId, - region: req?.body?.token_payload?.region, - owner: req?.body?.token_payload?.user_id, + region: token_payload?.region, + owner: token_payload?.user_id, }); - project.migration[0].name = req?.body?.name; - project.migration[0].description = req?.body?.description; + project.migration[0].name = name; + project.migration[0].description = description; project.migration[0].updated_at = new Date(); const updatedProject = await project.save(); @@ -127,6 +130,7 @@ const deleteMigration = async (req: Request) => { const orgId = req?.params?.orgId; const projectId = req?.params?.projectId; const migrationId = req?.params?.migrationId; + const { token_payload } = req.body; if (!isValidObjectId(migrationId)) throw new BadRequestError( @@ -137,8 +141,8 @@ const deleteMigration = async (req: Request) => { _id: projectId, "migration._id": migrationId, org_id: orgId, - region: req?.body?.token_payload?.region, - owner: req?.body?.token_payload?.user_id, + region: token_payload?.region, + owner: token_payload?.user_id, }; const project = await _getProject(projectId, filter); From d8e844382e6a34e94055079d15e19efe1d0922e1 Mon Sep 17 00:00:00 2001 From: hanoak20 Date: Thu, 25 Jan 2024 13:57:35 +0530 Subject: [PATCH 4/8] chore: Added a common req validator for project & migration routes. --- src/constants/index.ts | 2 + src/routes/projects.migrations.routes.ts | 13 ++++++- src/validators/index.ts | 2 + src/validators/project.validator.ts | 49 ++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 src/validators/project.validator.ts diff --git a/src/constants/index.ts b/src/constants/index.ts index c0ad1275a..7294e57fc 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -15,6 +15,7 @@ export type HttpErrorCodes = { export type ValidationErrors = { INVALID_EMAIL: string; EMAIL_LIMIT: string; + LENGTH_LIMIT: string; STRING_REQUIRED: string; INVALID_REGION: string; }; @@ -92,6 +93,7 @@ export const constants: ConstantType = { VALIDATION_ERRORS: { INVALID_EMAIL: "Given email ID is invalid.", EMAIL_LIMIT: "Email's max limit reached.", + LENGTH_LIMIT: "$'s max limit reached.", STRING_REQUIRED: "Provided $ should be a string.", INVALID_REGION: "Provided region doesn't exists.", }, diff --git a/src/routes/projects.migrations.routes.ts b/src/routes/projects.migrations.routes.ts index 35cbffd1c..9b73445ae 100644 --- a/src/routes/projects.migrations.routes.ts +++ b/src/routes/projects.migrations.routes.ts @@ -1,6 +1,7 @@ import express from "express"; import { migrationController } from "../controllers/projects.migrations.controller"; import { asyncRouter } from "../utils/async-router.utils"; +import validator from "../validators"; const router = express.Router({ mergeParams: true }); @@ -8,10 +9,18 @@ const router = express.Router({ mergeParams: true }); router.get("/", asyncRouter(migrationController.getMigration)); // Create a new project's migration route -router.post("/", asyncRouter(migrationController.createMigration)); +router.post( + "/", + validator("project"), + asyncRouter(migrationController.createMigration) +); // Update project's migration route -router.put("/:migrationId", asyncRouter(migrationController.updateMigration)); +router.put( + "/:migrationId", + validator("project"), + asyncRouter(migrationController.updateMigration) +); // Delete project's migration route router.delete( diff --git a/src/validators/index.ts b/src/validators/index.ts index 8a3f8de53..9b7d3ae15 100644 --- a/src/validators/index.ts +++ b/src/validators/index.ts @@ -2,11 +2,13 @@ import { Request, NextFunction, Response } from "express"; import { ValidationError } from "../utils/custom-errors.utils"; import { asyncRouter } from "../utils/async-router.utils"; import authValidator from "./auth.validator"; +import projectValidator from "./project.validator"; export default (route: string = "") => asyncRouter(async (req: Request, res: Response, next: NextFunction) => { const appValidators = { auth: authValidator, + project: projectValidator, }; const validator = appValidators[route as keyof typeof appValidators]; diff --git a/src/validators/project.validator.ts b/src/validators/project.validator.ts new file mode 100644 index 000000000..26580e288 --- /dev/null +++ b/src/validators/project.validator.ts @@ -0,0 +1,49 @@ +import { checkSchema } from "express-validator"; +import { constants } from "../constants"; + +export default checkSchema({ + name: { + in: "body", + isString: { + errorMessage: constants.VALIDATION_ERRORS.STRING_REQUIRED.replace( + "$", + "Name" + ), + bail: true, + }, + trim: true, + isLength: { + errorMessage: constants.VALIDATION_ERRORS.LENGTH_LIMIT.replace( + "$", + "Name" + ), + options: { + min: 1, + max: 200, + }, + bail: true, + }, + }, + description: { + in: "body", + isString: { + errorMessage: constants.VALIDATION_ERRORS.STRING_REQUIRED.replace( + "$", + "Description" + ), + bail: true, + }, + trim: true, + isLength: { + errorMessage: constants.VALIDATION_ERRORS.LENGTH_LIMIT.replace( + "$", + "Description" + ), + options: { + min: 1, + max: 255, + }, + bail: true, + }, + }, +}); From 812b83fb648d7ce2fbd02a4d9cf1c5a5cbbb2e13 Mon Sep 17 00:00:00 2001 From: hanoak20 Date: Thu, 25 Jan 2024 15:19:11 +0530 Subject: [PATCH 5/8] fix: upgraded helmet to 7.1.0 to fix Snyk error. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3437c87dc..7143f1144 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "express": "^4.18.2", "express-validator": "^7.0.1", "express-winston": "^4.2.0", - "helmet": "^6.0.1", + "helmet": "^7.1.0", "jsonwebtoken": "^9.0.2", "mongoose": "^8.0.4", "winston": "^3.11.0" From feb9ecd8aaab06a283b18a4c10cadeac83878b6e Mon Sep 17 00:00:00 2001 From: hanoak20 Date: Thu, 25 Jan 2024 18:17:25 +0530 Subject: [PATCH 6/8] chore: added auth.utils & getAllStack API endpoint in /org route, and others. --- src/constants/index.ts | 2 ++ src/controllers/org.controller.ts | 23 ++++++++++++++ src/routes/org.routes.ts | 16 ++++++++++ src/server.ts | 2 ++ src/services/org.service.ts | 50 +++++++++++++++++++++++++++++++ src/utils/auth.utils.ts | 13 ++++++++ src/utils/custom-errors.utils.ts | 6 ++++ 7 files changed, 112 insertions(+) create mode 100644 src/controllers/org.controller.ts create mode 100644 src/routes/org.routes.ts create mode 100644 src/services/org.service.ts create mode 100644 src/utils/auth.utils.ts diff --git a/src/constants/index.ts b/src/constants/index.ts index 7294e57fc..d637282ff 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -31,6 +31,7 @@ export type ConstantType = { }; export type HttpErrorTexts = { + UNAUTHORIZED: string; INTERNAL_ERROR: string; SOMETHING_WENT_WRONG: string; NO_CS_USER: string; @@ -69,6 +70,7 @@ export const constants: ConstantType = { UNPROCESSABLE_CONTENT: 422, }, HTTP_TEXTS: { + UNAUTHORIZED: "You're unauthorized to access this resource.", INTERNAL_ERROR: "Internal server error, please try again later.", SOMETHING_WENT_WRONG: "Something went wrong while processing your request, please try again.", diff --git a/src/controllers/org.controller.ts b/src/controllers/org.controller.ts new file mode 100644 index 000000000..8e0526af9 --- /dev/null +++ b/src/controllers/org.controller.ts @@ -0,0 +1,23 @@ +import { Request, Response } from "express"; +import { orgService } from "../services/org.service"; + +const getAllStacks = async (req: Request, res: Response) => { + const resp = await orgService.getAllStacks(req); + res.status(resp?.status).json(resp?.data); +}; + +const createStack = async (req: Request, res: Response) => { + const resp = await orgService.getAllStacks(req); + res.status(resp.status).json(resp.data); +}; + +const getLocales = async (req: Request, res: Response) => { + const resp = await orgService.getAllStacks(req); + res.status(resp.status).json(resp.data); +}; + +export const orgController = { + getAllStacks, + createStack, + getLocales, +}; diff --git a/src/routes/org.routes.ts b/src/routes/org.routes.ts new file mode 100644 index 000000000..2c6c54977 --- /dev/null +++ b/src/routes/org.routes.ts @@ -0,0 +1,16 @@ +import express from "express"; +import { orgController } from "../controllers/org.controller"; +import { asyncRouter } from "../utils/async-router.utils"; + +const router = express.Router({ mergeParams: true }); + +// GET all org stacks route +router.get("/stacks", asyncRouter(orgController.getAllStacks)); + +// Create a new stack route +router.post("/stacks", asyncRouter(orgController.createStack)); + +// GET all contentstack locales route +router.get("/locales", asyncRouter(orgController.getLocales)); + +export default router; diff --git a/src/server.ts b/src/server.ts index 6758cdf32..019bfac9c 100644 --- a/src/server.ts +++ b/src/server.ts @@ -6,6 +6,7 @@ import helmet from "helmet"; import authRoutes from "./routes/auth.routes"; import userRoutes from "./routes/user.routes"; import projectRoutes from "./routes/projects.routes"; +import orgRoutes from "./routes/org.routes"; import { errorMiddleware } from "./middlewares/error.middleware"; import loggerMiddleware from "./middlewares/logger.middleware"; import connectToDatabase from "./database"; @@ -31,6 +32,7 @@ try { // Routes app.use("/v2/auth", authRoutes); app.use("/v2/user", authenticateUser, userRoutes); + app.use("/v2/org/:orgId", authenticateUser, orgRoutes); app.use("/v2/org/:orgId/project", authenticateUser, projectRoutes); //For unmatched route patterns diff --git a/src/services/org.service.ts b/src/services/org.service.ts new file mode 100644 index 000000000..d317016e1 --- /dev/null +++ b/src/services/org.service.ts @@ -0,0 +1,50 @@ +import { Request } from "express"; +import { config } from "../config"; +import { safePromise } from "../utils/index"; +import https from "../utils/https.utils"; +import { LoginServiceType } from "../models/types"; +import getAuthtoken from "../utils/auth.utils"; + +const getAllStacks = async (req: Request): Promise => { + const orgId = req?.params?.orgId; + const { token_payload } = req.body; + + const authtoken = await getAuthtoken( + token_payload?.region, + token_payload?.user_id + ); + + const [err, res] = await safePromise( + https({ + method: "GET", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/stacks`, + headers: { + organization_uid: orgId, + authtoken, + }, + }) + ); + + if (err) + return { + data: err.response.data, + status: err.response.status, + }; + + return { + data: { + stacks: + res.data.stacks?.map((stack: any) => ({ + name: stack.name, + api_key: stack.api_key, + })) || [], + }, + status: res.status, + }; +}; + +export const orgService = { + getAllStacks, +}; diff --git a/src/utils/auth.utils.ts b/src/utils/auth.utils.ts new file mode 100644 index 000000000..053a77593 --- /dev/null +++ b/src/utils/auth.utils.ts @@ -0,0 +1,13 @@ +import AuthenticationModel from "../models/authentication"; +import { UnauthorizedError } from "../utils/custom-errors.utils"; + +export default async (region: string, userId: string) => { + const res = await AuthenticationModel.findOne({ + region: region, + user_id: userId, + }).lean(); + + if (!res?.authtoken) throw new UnauthorizedError(); + + return res?.authtoken; +}; diff --git a/src/utils/custom-errors.utils.ts b/src/utils/custom-errors.utils.ts index b5323b2b8..5853e9e6f 100644 --- a/src/utils/custom-errors.utils.ts +++ b/src/utils/custom-errors.utils.ts @@ -37,4 +37,10 @@ export class InternalServerError extends AppError { } } +export class UnauthorizedError extends AppError { + constructor(message: string = constants.HTTP_TEXTS.UNAUTHORIZED) { + super(constants.HTTP_CODES.UNAUTHORIZED, message); + } +} + // Add more custom error classes as needed From 6ee52b67fa7f66cd80756c7e90f5138a14a7d733 Mon Sep 17 00:00:00 2001 From: hanoak20 Date: Thu, 25 Jan 2024 18:33:37 +0530 Subject: [PATCH 7/8] chore: added /locales route. --- src/controllers/org.controller.ts | 2 +- src/services/org.service.ts | 33 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/controllers/org.controller.ts b/src/controllers/org.controller.ts index 8e0526af9..55673212d 100644 --- a/src/controllers/org.controller.ts +++ b/src/controllers/org.controller.ts @@ -12,7 +12,7 @@ const createStack = async (req: Request, res: Response) => { }; const getLocales = async (req: Request, res: Response) => { - const resp = await orgService.getAllStacks(req); + const resp = await orgService.getLocales(req); res.status(resp.status).json(resp.data); }; diff --git a/src/services/org.service.ts b/src/services/org.service.ts index d317016e1..401a92351 100644 --- a/src/services/org.service.ts +++ b/src/services/org.service.ts @@ -45,6 +45,39 @@ const getAllStacks = async (req: Request): Promise => { }; }; +const getLocales = async (req: Request): Promise => { + const { token_payload } = req.body; + + const authtoken = await getAuthtoken( + token_payload?.region, + token_payload?.user_id + ); + + const [err, res] = await safePromise( + https({ + method: "GET", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/locales?include_all=true`, + headers: { + authtoken, + }, + }) + ); + + if (err) + return { + data: err.response.data, + status: err.response.status, + }; + + return { + data: res.data, + status: res.status, + }; +}; + export const orgService = { getAllStacks, + getLocales, }; From 16a6c9f450207380485d63a6a40a79e0d9570e88 Mon Sep 17 00:00:00 2001 From: hanoak20 Date: Thu, 25 Jan 2024 18:56:46 +0530 Subject: [PATCH 8/8] chore: added createStack route's logic. --- src/controllers/org.controller.ts | 2 +- src/routes/org.routes.ts | 7 +++++- src/services/org.service.ts | 42 +++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/controllers/org.controller.ts b/src/controllers/org.controller.ts index 55673212d..9cf5b46e6 100644 --- a/src/controllers/org.controller.ts +++ b/src/controllers/org.controller.ts @@ -7,7 +7,7 @@ const getAllStacks = async (req: Request, res: Response) => { }; const createStack = async (req: Request, res: Response) => { - const resp = await orgService.getAllStacks(req); + const resp = await orgService.createStack(req); res.status(resp.status).json(resp.data); }; diff --git a/src/routes/org.routes.ts b/src/routes/org.routes.ts index 2c6c54977..c06a0654d 100644 --- a/src/routes/org.routes.ts +++ b/src/routes/org.routes.ts @@ -1,6 +1,7 @@ import express from "express"; import { orgController } from "../controllers/org.controller"; import { asyncRouter } from "../utils/async-router.utils"; +import validator from "../validators"; const router = express.Router({ mergeParams: true }); @@ -8,7 +9,11 @@ const router = express.Router({ mergeParams: true }); router.get("/stacks", asyncRouter(orgController.getAllStacks)); // Create a new stack route -router.post("/stacks", asyncRouter(orgController.createStack)); +router.post( + "/stacks", + validator("project"), + asyncRouter(orgController.createStack) +); // GET all contentstack locales route router.get("/locales", asyncRouter(orgController.getLocales)); diff --git a/src/services/org.service.ts b/src/services/org.service.ts index 401a92351..7c4e81498 100644 --- a/src/services/org.service.ts +++ b/src/services/org.service.ts @@ -45,6 +45,47 @@ const getAllStacks = async (req: Request): Promise => { }; }; +const createStack = async (req: Request): Promise => { + const orgId = req?.params?.orgId; + const { token_payload, name, description, master_locale } = req.body; + + const authtoken = await getAuthtoken( + token_payload?.region, + token_payload?.user_id + ); + + const [err, res] = await safePromise( + https({ + method: "POST", + url: `${config.CS_API[ + token_payload?.region as keyof typeof config.CS_API + ]!}/stacks`, + headers: { + organization_uid: orgId, + authtoken, + }, + data: { + stack: { + name, + description, + master_locale, + }, + }, + }) + ); + + if (err) + return { + data: err.response.data, + status: err.response.status, + }; + + return { + data: res.data, + status: res.status, + }; +}; + const getLocales = async (req: Request): Promise => { const { token_payload } = req.body; @@ -80,4 +121,5 @@ const getLocales = async (req: Request): Promise => { export const orgService = { getAllStacks, getLocales, + createStack, };