Skip to content

Commit

Permalink
Merge pull request #114 from contentstack/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
NamrataSane authored Dec 20, 2024
2 parents 360dd2b + c4b4442 commit 5ba70fa
Show file tree
Hide file tree
Showing 17 changed files with 510 additions and 1,301 deletions.
34 changes: 1 addition & 33 deletions api/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,7 @@ module.exports = {
browser: true,
es2021: true,
},
extends: ["prettier", "plugin:import/typescript"],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: "module",
project: "./tsconfig.json",
createDefaultProgram: true,
tsconfigRootDir: __dirname,
},
plugins: ["import", "@typescript-eslint"],

extends: ["prettier"],
rules: {
"max-len": "off",
"no-underscore-dangle": "off",
Expand All @@ -30,25 +17,6 @@ module.exports = {
},
},
],
"@typescript-eslint/naming-convention": [
"error",
{
selector: "default",
format: ["camelCase", "PascalCase", "UPPER_CASE"],
leadingUnderscore: "allow",
trailingUnderscore: "allow",
},
{
selector: "variable",
format: ["camelCase", "UPPER_CASE", "snake_case", "PascalCase"],
leadingUnderscore: "allow",
trailingUnderscore: "allow",
},
{
selector: "typeLike",
format: ["PascalCase"],
},
],
"func-names": [0],
"no-console": ["error", { allow: ["warn", "error", "info"] }],
},
Expand Down
10 changes: 3 additions & 7 deletions api/constants/index.ts → api/constants/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const constants: any = {
const constants = {
REQ_TIMEOUT: 17 * 1000,
EXTRACT_ID_REGX: /(\d+)/gm, // extracts the digits from the data as an ID for the error response
EXTRACT_ID_REGX: /\(\d+\)/gm, // extracts the digits from the data as an ID for the error response
HTTP_ERROR_CODES: {
OK: 200,
BAD_REQ: 400,
Expand All @@ -15,13 +15,9 @@ const constants: any = {
},
FETCH_PRODUCT_LIMIT: 250,
HTTP_RESPONSE_HEADERS: {
// eslint-disable-next-line @typescript-eslint/naming-convention
"Access-Control-Allow-Origin": "*",
// eslint-disable-next-line @typescript-eslint/naming-convention
"Content-type": "application/json",
// eslint-disable-next-line @typescript-eslint/naming-convention
"Access-Control-Allow-Headers": "Content-Type",
// eslint-disable-next-line @typescript-eslint/naming-convention
"Access-Control-Expose-Headers": "authToken",
},
LOGS: {
Expand All @@ -36,4 +32,4 @@ const constants: any = {
},
};

export default constants;
module.exports = constants;
47 changes: 27 additions & 20 deletions api/handler/index.ts → api/handler/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios from "axios";
import constants from "../constants";
import root_config from "../root_config";
const axios = require("axios");
const constants = require("../constants");
const root_config = require("../root_config");

/**
* Makes a third-party API call with the provided options.
Expand All @@ -15,11 +15,11 @@ import root_config from "../root_config";
* It handles errors by returning a default response for `404 Not Found` errors
* and throws an error for other types of failures.
*/
export const _makeApiCall: any = async (opts: any) => {
const _makeApiCall = async (opts) => {
try {
const res: any = await axios({ ...opts, timeout: constants.REQ_TIMEOUT });
const res = await axios({ ...opts, timeout: constants.REQ_TIMEOUT });
return res?.data;
} catch (e: any) {
} catch (e) {
throw e;
}
};
Expand All @@ -31,10 +31,7 @@ export const _makeApiCall: any = async (opts: any) => {
* @param {Object} productPayload - Payload containing additional data for the request.
* @returns {Promise<Object>} - The product data.
*/
export const getProductByID: any = async (
productQuery: any,
productPayload: any
) => {
const getProductByID = async (productQuery, productPayload) => {
let response = await root_config.getSingleProduct(
productQuery,
productPayload
Expand All @@ -52,9 +49,9 @@ export const getProductByID: any = async (
* @param {Object} productCategoryPayload - Payload containing additional data for the request.
* @returns {Promise<Object>} - The products and categories data.
*/
export const getAllProductsAndCategories: any = async (
productCategoryQuery: any,
productCategoryPayload: any
const getAllProductsAndCategories = async (
productCategoryQuery,
productCategoryPayload
) => {
let response = {};
if (root_config.ENDPOINTS_CONFIG.getSeparateProductsAndCategories) {
Expand Down Expand Up @@ -86,9 +83,9 @@ export const getAllProductsAndCategories: any = async (
* @param {Object} productCategoryPayload - Payload containing additional data for the request.
* @returns {Promise<Object>} - The selected products and categories data.
*/
export const getSelectedProductsAndCategories: any = async (
productCategoryQuery: any,
productCategoryPayload: any
const getSelectedProductsAndCategories = async (
productCategoryQuery,
productCategoryPayload
) => {
let response = {};
if (root_config.ENDPOINTS_CONFIG.getSeparateProductsAndCategories) {
Expand All @@ -115,10 +112,11 @@ export const getSelectedProductsAndCategories: any = async (
/**
* Filters products based on the provided categories.
*/
export const filterByCategory: any = async (data: any, key: any) => {
const filterByCategory = async (data, key) => {
let response = await root_config.filterProductsByCategory(data, key);
return response;
};

/**
* Retrieves API validation for configuration page keys.
*
Expand All @@ -132,13 +130,22 @@ export const filterByCategory: any = async (data: any, key: any) => {
*
* @returns {Promise<any>} - A promise that resolves to the API validation response.
*/
export const getApiValidationForConfigPageKeys: any = async (
apkSdkInstallationData: any,
query: any
const getApiValidationForConfigPageKeys = async (
apkSdkInstallationData,
query
) => {
let response = await root_config.retrieveConfigPageValidation(
apkSdkInstallationData,
query
);
return response;
};

module.exports = {
_makeApiCall,
getProductByID,
getAllProductsAndCategories,
getSelectedProductsAndCategories,
filterByCategory,
getApiValidationForConfigPageKeys,
};
124 changes: 124 additions & 0 deletions api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Import necessary modules
const CryptoJS = require("crypto-js");
const root_config = require("../root_config");
const constants = require("./constants");
const {
getAllProductsAndCategories,
getProductByID,
getSelectedProductsAndCategories,
filterByCategory,
getApiValidationForConfigPageKeys,
} = require("./handler");

// Utility function to check if a value is empty
exports._isEmpty = (val) =>
val === undefined ||
val === null ||
(typeof val === "object" && !Object.keys(val)?.length) ||
(typeof val === "string" && !val.trim()?.length);

// Function to decrypt a value
exports.decrypt = (value) => {
try {
const decryptionKey = `${process.env.DECRYPTION_KEY}`;
const bytes = CryptoJS.AES.decrypt(value, decryptionKey);
return bytes.toString(CryptoJS.enc.Utf8);
} catch (e) {
console.error("Decryption failed:", e);
return value; // Return as is if decryption fails
}
};

// Function to process and decrypt sensitive keys in a request body
exports.processRequestBody = (requestBody) => {
const decryptSensitiveKeys = (obj) => {
if (typeof obj === "object" && obj !== null) {
if (Array.isArray(obj)) {
return obj.map((item) => decryptSensitiveKeys(item));
} else {
const result = {};
Object.keys(obj).forEach((key) => {
if (root_config?.SENSITIVE_CONFIG_KEYS?.includes(key)) {
result[key] = exports.decrypt(obj?.[key]);
} else if (typeof obj?.[key] === "object") {
result[key] = decryptSensitiveKeys(obj?.[key]);
} else {
result[key] = obj?.[key];
}
});
return result;
}
}
return obj;
};

// Decrypt multi_config_keys if present
if (requestBody?.multi_config_keys) {
requestBody.multi_config_keys = decryptSensitiveKeys(
requestBody.multi_config_keys
);
}

// Decrypt custom_keys if present
if (requestBody?.custom_keys) {
requestBody.custom_keys = decryptSensitiveKeys(requestBody.custom_keys);
}

return requestBody;
};

// Main handler function for processing requests
exports.handler = async ({ queryStringParameters: query, body }) => {
let message;
let statusCode = constants.HTTP_ERROR_CODES.OK;

//eslint-disable-next-line no-param-reassign
body = processRequestBody(body);

//eslint-disable-next-line no-param-reassign
if (typeof body === "string") body = JSON.parse(body);

try {
console.info(constants.LOGS.REQ_BODY, body);
console.info(constants.LOGS.QUERY_PARAMS, query);

// Check if the body is empty and throw an error if it is
if (exports._isEmpty(body)) {
throw {
statusCode: constants.HTTP_ERROR_CODES.BAD_REQ,
message: constants.HTTP_ERROR_TEXTS.QUERY_MISSING,
};
}

// Determine request type and process accordingly
if (query?.["sku:in"] || query?.["id:in"]) {
message = await getSelectedProductsAndCategories(query, body);
} else if (query?.["categories:in"]) {
message = await filterByCategory(query, body);
} else if (query?.id) {
message = await getProductByID(query, body);
} else if (query?.type === "isApiValidationEnabled") {
message = await getApiValidationForConfigPageKeys(body, query);
} else {
message = await getAllProductsAndCategories(query, body);
}
} catch (e) {
statusCode =
e?.response?.status ?? constants.HTTP_ERROR_CODES.SOMETHING_WRONG;
message =
e?.response?.data?.message ??
constants.HTTP_ERROR_TEXTS.SOMETHING_WENT_WRONG;
console.error(
`Error: stack_api_key: ${query?.stack_apiKey}, status_code: ${statusCode}, error_message: ${message}, stack: ${e?.stack}`
);
}

return {
statusCode,
headers: {
...constants.HTTP_RESPONSE_HEADERS,
authToken: "",
},
body: message, // For Localhost or JSON.stringify(message) for AWS Lambda
};
};
73 changes: 0 additions & 73 deletions api/index.ts

This file was deleted.

Loading

0 comments on commit 5ba70fa

Please sign in to comment.