Add skeleton

This commit is contained in:
2025-09-17 13:28:50 +07:00
parent f4ab31b436
commit 945e0083d2
5 changed files with 147 additions and 0 deletions

24
helpers/error.js Normal file
View File

@@ -0,0 +1,24 @@
const { logger } = require("../utils/logger");
class ErrorHandler extends Error {
constructor(statusCode, message) {
super();
this.status = "error";
this.statusCode = statusCode;
this.message = message;
}
}
const handleError = (err, req, res, next) => {
const { statusCode, message } = err;
logger.error(err);
res.status(statusCode || 500).json({
status: "error",
statusCode: statusCode || 500,
message: statusCode === 500 ? "An error occurred" : message,
});
next();
};
module.exports = {
ErrorHandler,
handleError,
};

12
helpers/hashPassword.js Normal file
View File

@@ -0,0 +1,12 @@
const bcrypt = require("bcrypt");
const hashPassword = async (password) => {
const salt = await bcrypt.genSalt();
const hashedPassword = await bcrypt.hash(password, salt);
return hashedPassword;
};
const comparePassword = async (password, passwordHash) =>
await bcrypt.compare(password, passwordHash);
module.exports = { hashPassword, comparePassword };

13
helpers/test_helper.js Normal file
View File

@@ -0,0 +1,13 @@
const pool = require("../config");
const usersInDb = async () => {
const users = await pool.query("SELECT * FROM USERS");
return users.rows;
};
const productsInDb = async () => {
const products = await pool.query("SELECT * FROM products");
return products.rows;
};
module.exports = { usersInDb, productsInDb };

89
helpers/utils.js Normal file
View File

@@ -0,0 +1,89 @@
const setResponse = async (data = [], message = "success", statusCode = 200) => {
const response = {
data,
total: data.length,
message,
statusCode
}
return response
};
const setResponsePaging = async (data = [], total, limit, page, message = "success", statusCode = 200) => {
const totalPages = Math.ceil(total / limit);
const response = {
message,
statusCode,
data,
total: data.length,
paging: {
total,
limit,
page,
page_total: totalPages
}
}
return response
};
const setPaging = async (total, limit, page) => {
const totalPages = Math.ceil(total / limit);
const response = {
total,
limit,
page,
page_total: totalPages
}
return response
};
function convertId(items, id, fieldId = "id", fieldName = "name") {
var match = ""
items.forEach(element => {
if (element[fieldId] == id) {
match = element[fieldName]
}
});
return match
}
function formatToYYYYMMDD(date) {
return new Intl.DateTimeFormat('id-ID', {
timeZone: 'Asia/Jakarta',
year: 'numeric',
month: '2-digit',
day: '2-digit',
}).format(date).split('/').reverse().join('-'); // Ubah format dari dd/mm/yyyy ke yyyy-mm-dd
}
function ensureArray(param) {
return Array.isArray(param) ? param : [param];
}
function orderByClauseQuery(orderParams) {
orderParams = ensureArray(orderParams)
// Transform order parameters to SQL ORDER BY syntax
const validDirections = ['ASC', 'DESC'];
const orderConditions = orderParams.map(param => {
const [field, direction] = param.split(':');
if (!validDirections.includes(direction.toUpperCase())) {
throw new Error(`Invalid direction: ${direction}`);
}
return `${field} ${direction}`;
});
// Gabungkan dengan koma untuk digunakan dalam query
const orderByClause = orderConditions.join(', ');
return orderByClause
}
module.exports = { setResponse, setResponsePaging, setPaging, convertId, formatToYYYYMMDD, orderByClauseQuery };

9
helpers/validateUser.js Normal file
View File

@@ -0,0 +1,9 @@
const validateUser = (email, password) => {
const validEmail = typeof email === "string" && email.trim() !== "";
const validPassword =
typeof password === "string" && password.trim().length >= 6;
return validEmail && validPassword;
};
module.exports = validateUser;