Compare commits
20 Commits
3e6877ee07
...
a6c2e7fc7e
| Author | SHA1 | Date | |
|---|---|---|---|
| a6c2e7fc7e | |||
| 45968832f0 | |||
| cf37732ebe | |||
| 20b70edaa6 | |||
| b16e65463d | |||
| 58cb0c8425 | |||
| 0ae39aa504 | |||
| 9ad16fcff7 | |||
| 453b5eb5af | |||
| 76c5eef2f7 | |||
| f9d3bd913f | |||
| 4b60f922ee | |||
| a4ef76e74e | |||
| 33e70721d9 | |||
| 8fca2d3cd2 | |||
| a632791a4d | |||
| 2eec70b7e3 | |||
| ba7f746433 | |||
| ddf9784213 | |||
| 48cb3af91d |
@@ -26,16 +26,23 @@ class AuthController {
|
|||||||
|
|
||||||
const { user, tokens } = await AuthService.register(value);
|
const { user, tokens } = await AuthService.register(value);
|
||||||
|
|
||||||
// Set refresh token in cookie
|
// Set refresh token di cookie
|
||||||
res.cookie('refreshToken', tokens.refreshToken, {
|
res.cookie('refreshToken', tokens.refreshToken, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: false, //masih dev
|
secure: false, // masih dev
|
||||||
sameSite: 'lax',
|
sameSite: 'lax',
|
||||||
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 hari
|
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 hari
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(201).json(
|
return res.status(201).json(
|
||||||
setResponse({ user, accessToken: tokens.accessToken }, 'User registered successfully', 201)
|
setResponse(
|
||||||
|
{
|
||||||
|
user: { ...user, approved: false },
|
||||||
|
accessToken: tokens.accessToken
|
||||||
|
},
|
||||||
|
'User registered successfully. Waiting for admin approval.',
|
||||||
|
201
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return res.status(err.statusCode || 500).json(
|
return res.status(err.statusCode || 500).json(
|
||||||
@@ -68,7 +75,7 @@ class AuthController {
|
|||||||
|
|
||||||
const { user, tokens } = await AuthService.login({ email, password });
|
const { user, tokens } = await AuthService.login({ email, password });
|
||||||
|
|
||||||
// Set refresh token in cookie
|
// Set refresh token di cookie
|
||||||
res.cookie('refreshToken', tokens.refreshToken, {
|
res.cookie('refreshToken', tokens.refreshToken, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: false, // masih dev
|
secure: false, // masih dev
|
||||||
@@ -77,7 +84,14 @@ class AuthController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).json(
|
return res.status(200).json(
|
||||||
setResponse({ user, accessToken: tokens.accessToken }, 'Login successful', 200)
|
setResponse(
|
||||||
|
{
|
||||||
|
user: { ...user, approved: true },
|
||||||
|
accessToken: tokens.accessToken
|
||||||
|
},
|
||||||
|
'Login successful',
|
||||||
|
200
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return res.status(err.statusCode || 500).json(
|
return res.status(err.statusCode || 500).json(
|
||||||
|
|||||||
@@ -1,172 +1,157 @@
|
|||||||
const userService = require("../services/user.service");
|
const userService = require("../services/user.service");
|
||||||
const { ErrorHandler } = require("../helpers/error");
|
const { ErrorHandler } = require("../helpers/error");
|
||||||
const { hashPassword } = require("../helpers/hashPassword");
|
const { setResponse } = require("../helpers/utils");
|
||||||
const { setResponse, setPaging, setResponsePaging } = require("../helpers/utils");
|
|
||||||
const Joi = require("joi");
|
const Joi = require("joi");
|
||||||
|
const { userSchema } = require("../helpers/validation");
|
||||||
|
|
||||||
// Definisikan skema validasi
|
class UserController {
|
||||||
const validateTerm = Joi.object({
|
// Get all users
|
||||||
user_fullname: Joi.string().max(255).required(),
|
static async getAllUsers(req, res) {
|
||||||
user_name: Joi.string().max(255).required(),
|
try {
|
||||||
user_email: Joi.string().max(255).email().allow(null),
|
const users = await userService.getAllUsers();
|
||||||
user_password: Joi.string().max(255).required(),
|
return res.status(200).json(setResponse(users, "Users retrieved successfully", 200));
|
||||||
role_id: Joi.number().integer().allow(null),
|
} catch (error) {
|
||||||
is_active: Joi.boolean().required()
|
return res
|
||||||
});
|
.status(error.statusCode || 500)
|
||||||
|
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||||
const getAllUsers = async (req, res) => {
|
|
||||||
|
|
||||||
const {
|
|
||||||
page = 1,
|
|
||||||
limit = 10,
|
|
||||||
fullname: userFullname,
|
|
||||||
username: userName,
|
|
||||||
is_active: isActive,
|
|
||||||
criteria,
|
|
||||||
tenantID,
|
|
||||||
} = req.query
|
|
||||||
|
|
||||||
const offset = (page - 1) * limit;
|
|
||||||
|
|
||||||
const filterQuery = {
|
|
||||||
fixed: {
|
|
||||||
limit, offset, tenantID
|
|
||||||
},
|
|
||||||
filterQuery: [
|
|
||||||
{
|
|
||||||
type: 'string',
|
|
||||||
column: 'user_fullname',
|
|
||||||
param: userFullname
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'string',
|
|
||||||
column: 'user_name',
|
|
||||||
param: userName
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'number',
|
|
||||||
column: 'is_active',
|
|
||||||
param: isActive
|
|
||||||
}
|
|
||||||
],
|
|
||||||
filterCriteria:
|
|
||||||
{
|
|
||||||
criteria,
|
|
||||||
column: [
|
|
||||||
'user_fullname', 'user_name'
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await userService.getAllUsers(filterQuery)
|
// Get user by ID
|
||||||
const response = await setResponsePaging(results.data, results.total, parseInt(limit), parseInt(page))
|
static async getUserById(req, res) {
|
||||||
|
try {
|
||||||
res.status(response.statusCode).json(response)
|
const { id } = req.params;
|
||||||
};
|
const user = await userService.getUserById(id);
|
||||||
|
return res.status(200).json(setResponse(user, "User retrieved successfully", 200));
|
||||||
const getAllStatusUsers = async (req, res) => {
|
} catch (error) {
|
||||||
|
return res
|
||||||
const results = await userService.getAllStatusUsers();
|
.status(error.statusCode || 500)
|
||||||
const response = await setResponse(results)
|
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||||
|
}
|
||||||
res.status(response.statusCode).json(response);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createUser = async (req, res) => {
|
|
||||||
|
|
||||||
// Lakukan validasi
|
|
||||||
const { error } = validateTerm.validate(req.body, { stripUnknown: true });
|
|
||||||
if (error) {
|
|
||||||
const response = await setResponse([], error.details[0].message, 400)
|
|
||||||
return res.status(response.statusCode).json(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await userService.createUser({
|
// Create new user
|
||||||
userFullname: req.body.user_fullname,
|
static async createUser(req, res) {
|
||||||
userName: req.body.user_name,
|
try {
|
||||||
userEmail: req.body.user_email,
|
const { error, value } = userSchema.validate(req.body, { abortEarly: false });
|
||||||
userPassword: req.body.user_password,
|
|
||||||
roleId: req.body.role_id,
|
|
||||||
isActive: req.body.is_active, // default 1 jika tidak dikirim
|
|
||||||
userID: req.body.userID,
|
|
||||||
tenantID: req.body.tenantID
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await setResponse(results);
|
if (error) {
|
||||||
|
const validationErrors = error.details.map((err) => err.message);
|
||||||
|
throw new ErrorHandler(400, validationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
res.status(response.statusCode).json(response);
|
// Kirim approved_by dari user yang bikin
|
||||||
};
|
const result = await userService.createUser({
|
||||||
|
...value,
|
||||||
|
approved_by: req.user.user_id
|
||||||
|
});
|
||||||
|
|
||||||
const getUserById = async (req, res) => {
|
return res.status(201).json(setResponse(result, "User created successfully", 201));
|
||||||
const { id } = req.params;
|
} catch (error) {
|
||||||
|
return res
|
||||||
const results = await userService.getUserById(id);
|
.status(error.statusCode || 500)
|
||||||
const response = await setResponse(results)
|
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||||
|
}
|
||||||
res.status(response.statusCode).json(response);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getUserProfile = async (req, res) => {
|
|
||||||
const { id } = req.user;
|
|
||||||
|
|
||||||
const results = await userService.getUserById(id);
|
|
||||||
const response = await setResponse(results)
|
|
||||||
|
|
||||||
res.status(response.statusCode).json(response);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateUser = async (req, res) => {
|
|
||||||
|
|
||||||
const { id } = req.params;
|
|
||||||
|
|
||||||
// Lakukan validasi
|
|
||||||
const { error } = validateTerm.validate(req.body, { stripUnknown: true });
|
|
||||||
if (error) {
|
|
||||||
const response = await setResponse([], error.details[0].message, 400)
|
|
||||||
return res.status(response.statusCode).json(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await userService.updateUser({
|
// Update user
|
||||||
userFullname: req.body.user_fullname,
|
static async updateUser(req, res) {
|
||||||
userName: req.body.user_name,
|
try {
|
||||||
userEmail: req.body.user_email,
|
const { id } = req.params;
|
||||||
userPassword: req.body.user_password,
|
const {
|
||||||
roleId: req.body.role_id,
|
fullname,
|
||||||
isActive: req.body.is_active, // default 1 jika tidak dikirim
|
name,
|
||||||
userID: req.body.userID,
|
email,
|
||||||
tenantID: req.body.tenantID,
|
phone,
|
||||||
id
|
role_id,
|
||||||
});
|
is_sa,
|
||||||
|
is_active,
|
||||||
|
is_approve
|
||||||
|
} = req.body;
|
||||||
|
|
||||||
const response = await setResponse(results);
|
const result = await userService.updateUser({
|
||||||
|
user_id: parseInt(id, 10),
|
||||||
|
fullname,
|
||||||
|
name,
|
||||||
|
email,
|
||||||
|
phone,
|
||||||
|
role_id,
|
||||||
|
is_sa,
|
||||||
|
is_active,
|
||||||
|
is_approve
|
||||||
|
});
|
||||||
|
|
||||||
res.status(response.statusCode).json(response);
|
console.log("PARAM ID:", req.params);
|
||||||
};
|
console.log("BODY:", req.body);
|
||||||
|
|
||||||
const deleteUser = async (req, res) => {
|
return res.status(200).json(setResponse(result, "User updated successfully", 200));
|
||||||
const { id } = req.params;
|
} catch (error) {
|
||||||
const userID = req.userID
|
return res
|
||||||
|
.status(error.statusCode || 500)
|
||||||
|
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const results = await userService.deleteUser(id, userID);
|
// Delete user
|
||||||
const response = await setResponse(results)
|
static async deleteUser(req, res) {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const deletedBy = req.user?.user_id;
|
||||||
|
|
||||||
res.status(response.statusCode).json(response);
|
const result = await userService.deleteUser(id, deletedBy);
|
||||||
};
|
return res.status(200).json(setResponse(result, "User deleted successfully", 200));
|
||||||
|
} catch (error) {
|
||||||
|
return res
|
||||||
|
.status(error.statusCode || 500)
|
||||||
|
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getAllRoles = async (req, res) => {
|
// Change user password
|
||||||
const results = await userService.getAllRoles(req.body.tenantID);
|
static async changePassword(req, res) {
|
||||||
const response = await setResponse(results)
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const { new_password } = req.body;
|
||||||
|
|
||||||
res.status(response.statusCode).json(response);
|
if (!id || !new_password) {
|
||||||
};
|
throw new ErrorHandler(400, "user_id and new_password are required");
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
const result = await userService.changeUserPassword(user_id, new_password);
|
||||||
getAllUsers,
|
return res.status(200).json(setResponse(result, "Password changed successfully", 200));
|
||||||
createUser,
|
} catch (error) {
|
||||||
getUserById,
|
return res
|
||||||
updateUser,
|
.status(error.statusCode || 500)
|
||||||
deleteUser,
|
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||||
getUserProfile,
|
}
|
||||||
getAllRoles,
|
}
|
||||||
getAllStatusUsers
|
|
||||||
};
|
// Get all status users
|
||||||
|
static async getAllStatusUsers(req, res) {
|
||||||
|
try {
|
||||||
|
const result = await userService.getAllStatusUsers();
|
||||||
|
return res.status(200).json(setResponse(result, "Status list retrieved successfully", 200));
|
||||||
|
} catch (error) {
|
||||||
|
return res
|
||||||
|
.status(error.statusCode || 500)
|
||||||
|
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Approve user
|
||||||
|
static async approveUser(req, res) {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const approverId = req.user?.user_id || null;
|
||||||
|
|
||||||
|
const result = await userService.approveUser(id, approverId);
|
||||||
|
return res.status(200).json(setResponse(result, "User approved successfully", 200));
|
||||||
|
} catch (error) {
|
||||||
|
return res
|
||||||
|
.status(error.statusCode || 500)
|
||||||
|
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = UserController;
|
||||||
|
|||||||
@@ -1,24 +1,46 @@
|
|||||||
const pool = require("../config");
|
const pool = require("../config");
|
||||||
|
|
||||||
// Get all brands
|
// Get all brands
|
||||||
const getAllBrandsDb = async () => {
|
const getAllBrandsDb = async (filters = {}) => {
|
||||||
|
const { whereConditions, queryParams } = pool.buildFilterQuery([
|
||||||
|
{ column: "b.brand_name", param: filters.brand_name, type: "string" },
|
||||||
|
{ column: "b.created_by", param: filters.created_by, type: "number" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const whereClause = whereConditions.length ? `AND ${whereConditions.join(" AND ")}` : "";
|
||||||
|
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT *
|
SELECT
|
||||||
FROM m_brands
|
b.brand_id,
|
||||||
WHERE deleted_at IS NULL
|
b.brand_name,
|
||||||
ORDER BY brand_id ASC
|
b.created_at,
|
||||||
|
b.updated_at,
|
||||||
|
b.deleted_at,
|
||||||
|
b.created_by,
|
||||||
|
b.updated_by,
|
||||||
|
b.deleted_by
|
||||||
|
FROM m_brands b
|
||||||
|
WHERE b.deleted_at IS NULL ${whereClause}
|
||||||
|
ORDER BY b.brand_id ASC
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText);
|
const result = await pool.query(queryText, queryParams);
|
||||||
return result.recordset;
|
return result.recordset;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get brand by ID
|
// Get brand by ID
|
||||||
const getBrandByIdDb = async (id) => {
|
const getBrandByIdDb = async (id) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT *
|
SELECT
|
||||||
|
brand_id,
|
||||||
|
brand_name,
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
deleted_at,
|
||||||
|
created_by,
|
||||||
|
updated_by,
|
||||||
|
deleted_by
|
||||||
FROM m_brands
|
FROM m_brands
|
||||||
WHERE brand_id = $1
|
WHERE brand_id = $1 AND deleted_at IS NULL
|
||||||
AND deleted_at IS NULL
|
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText, [id]);
|
const result = await pool.query(queryText, [id]);
|
||||||
return result.recordset[0];
|
return result.recordset[0];
|
||||||
@@ -27,10 +49,17 @@ const getBrandByIdDb = async (id) => {
|
|||||||
// Get brand by name
|
// Get brand by name
|
||||||
const getBrandByNameDb = async (name) => {
|
const getBrandByNameDb = async (name) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT *
|
SELECT
|
||||||
|
brand_id,
|
||||||
|
brand_name,
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
deleted_at,
|
||||||
|
created_by,
|
||||||
|
updated_by,
|
||||||
|
deleted_by
|
||||||
FROM m_brands
|
FROM m_brands
|
||||||
WHERE brand_name = $1
|
WHERE brand_name = $1 AND deleted_at IS NULL
|
||||||
AND deleted_at IS NULL
|
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText, [name]);
|
const result = await pool.query(queryText, [name]);
|
||||||
return result.recordset[0];
|
return result.recordset[0];
|
||||||
@@ -38,18 +67,24 @@ const getBrandByNameDb = async (name) => {
|
|||||||
|
|
||||||
// Create brand
|
// Create brand
|
||||||
const createBrandDb = async (data) => {
|
const createBrandDb = async (data) => {
|
||||||
const { query: queryText, values } = pool.buildDynamicInsert("m_brands", data);
|
const { query, values } = pool.buildDynamicInsert("m_brands", {
|
||||||
const result = await pool.query(queryText, values);
|
...data,
|
||||||
|
created_at: new Date(),
|
||||||
|
});
|
||||||
|
const result = await pool.query(query, values);
|
||||||
const insertedId = result.recordset[0]?.inserted_id;
|
const insertedId = result.recordset[0]?.inserted_id;
|
||||||
if (!insertedId) return null;
|
if (!insertedId) return null;
|
||||||
|
|
||||||
return getBrandByIdDb(insertedId);
|
return getBrandByIdDb(insertedId);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update brand
|
// Update brand
|
||||||
const updateBrandDb = async (id, data) => {
|
const updateBrandDb = async (id, data) => {
|
||||||
const { query: queryText, values } = pool.buildDynamicUpdate("m_brands", data, { brand_id: id });
|
const { query, values } = pool.buildDynamicUpdate(
|
||||||
await pool.query(queryText, values);
|
"m_brands",
|
||||||
|
{ ...data, updated_at: new Date() },
|
||||||
|
{ brand_id: id }
|
||||||
|
);
|
||||||
|
await pool.query(query, values);
|
||||||
return getBrandByIdDb(id);
|
return getBrandByIdDb(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,8 +94,7 @@ const softDeleteBrandDb = async (id, deletedBy) => {
|
|||||||
UPDATE m_brands
|
UPDATE m_brands
|
||||||
SET deleted_at = GETDATE(),
|
SET deleted_at = GETDATE(),
|
||||||
deleted_by = $1
|
deleted_by = $1
|
||||||
WHERE brand_id = $2
|
WHERE brand_id = $2 AND deleted_at IS NULL
|
||||||
AND deleted_at IS NULL
|
|
||||||
`;
|
`;
|
||||||
await pool.query(queryText, [deletedBy, id]);
|
await pool.query(queryText, [deletedBy, id]);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,85 +1,69 @@
|
|||||||
const pool = require("../config");
|
const pool = require("../config");
|
||||||
|
|
||||||
// Get all devices
|
// Get all devices
|
||||||
const getAllDevicesDb = async () => {
|
const getAllDevicesDb = async (searchParams = {}) => {
|
||||||
|
const { whereConditions, queryParams } = pool.buildFilterQuery([
|
||||||
|
{ column: "d.device_name", param: searchParams.name, type: "string" },
|
||||||
|
{ column: "d.device_code", param: searchParams.code, type: "string" },
|
||||||
|
{ column: "d.device_location", param: searchParams.location, type: "string" },
|
||||||
|
{ column: "b.brand_name", param: searchParams.brand, type: "string" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const whereClause = whereConditions.length
|
||||||
|
? `AND ${whereConditions.join(" AND ")}`
|
||||||
|
: "";
|
||||||
|
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT *
|
SELECT d.*, b.brand_name
|
||||||
FROM m_device
|
FROM m_device d
|
||||||
WHERE deleted_at IS NULL
|
LEFT JOIN m_brands b ON d.brand_id = b.brand_id
|
||||||
ORDER BY device_id ASC
|
WHERE d.deleted_at IS NULL ${whereClause}
|
||||||
|
ORDER BY d.device_id ASC
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText);
|
const result = await pool.query(queryText, queryParams);
|
||||||
return result.recordset;
|
return result.recordset;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Search devices by keyword
|
|
||||||
const searchDevicesDb = async (keyword) => {
|
|
||||||
const queryText = `
|
|
||||||
SELECT *
|
|
||||||
FROM m_device
|
|
||||||
WHERE deleted_at IS NULL
|
|
||||||
AND (
|
|
||||||
device_name LIKE '%' + $1 + '%'
|
|
||||||
OR device_code LIKE '%' + $1 + '%'
|
|
||||||
OR device_location LIKE '%' + $1 + '%'
|
|
||||||
OR ip_address LIKE '%' + $1 + '%'
|
|
||||||
OR device_description LIKE '%' + $1 + '%'
|
|
||||||
)
|
|
||||||
ORDER BY device_id ASC
|
|
||||||
`;
|
|
||||||
const result = await pool.query(queryText, [keyword]);
|
|
||||||
return result.recordset;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get device by ID
|
|
||||||
const getDeviceByIdDb = async (id) => {
|
const getDeviceByIdDb = async (id) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT *
|
SELECT d.*, b.brand_name
|
||||||
FROM m_device
|
FROM m_device d
|
||||||
WHERE device_id = $1
|
LEFT JOIN m_brands b ON d.brand_id = b.brand_id
|
||||||
AND deleted_at IS NULL
|
WHERE d.device_id = $1 AND d.deleted_at IS NULL
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText, [id]);
|
const result = await pool.query(queryText, [id]);
|
||||||
return result.recordset[0];
|
return result.recordset[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get device by device_code
|
|
||||||
const getDeviceByCodeDb = async (code) => {
|
const getDeviceByCodeDb = async (code) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT *
|
SELECT d.*, b.brand_name
|
||||||
FROM m_device
|
FROM m_device d
|
||||||
WHERE device_code = $1
|
LEFT JOIN m_brands b ON d.brand_id = b.brand_id
|
||||||
AND deleted_at IS NULL
|
WHERE d.device_code = $1 AND d.deleted_at IS NULL
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText, [code]);
|
const result = await pool.query(queryText, [code]);
|
||||||
return result.recordset[0];
|
return result.recordset[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create device
|
|
||||||
const createDeviceDb = async (data) => {
|
const createDeviceDb = async (data) => {
|
||||||
const { query: queryText, values } = pool.buildDynamicInsert("m_device", data);
|
const { query: queryText, values } = pool.buildDynamicInsert("m_device", data);
|
||||||
const result = await pool.query(queryText, values);
|
const result = await pool.query(queryText, values);
|
||||||
const insertedId = result.recordset[0]?.inserted_id;
|
const insertedId = result.recordset[0]?.inserted_id;
|
||||||
if (!insertedId) return null;
|
return insertedId ? await getDeviceByIdDb(insertedId) : null;
|
||||||
|
|
||||||
return getDeviceByIdDb(insertedId);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update device
|
|
||||||
const updateDeviceDb = async (id, data) => {
|
const updateDeviceDb = async (id, data) => {
|
||||||
const { query: queryText, values } = pool.buildDynamicUpdate("m_device", data, { device_id: id });
|
const { query: queryText, values } = pool.buildDynamicUpdate("m_device", data, { device_id: id });
|
||||||
await pool.query(queryText, values);
|
await pool.query(`${queryText} AND deleted_at IS NULL`, values);
|
||||||
return getDeviceByIdDb(id);
|
return getDeviceByIdDb(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Soft delete device
|
|
||||||
const softDeleteDeviceDb = async (id, deletedBy) => {
|
const softDeleteDeviceDb = async (id, deletedBy) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
UPDATE m_device
|
UPDATE m_device
|
||||||
SET deleted_at = GETDATE(),
|
SET deleted_at = GETDATE(), deleted_by = $1
|
||||||
deleted_by = $1
|
WHERE device_id = $2 AND deleted_at IS NULL
|
||||||
WHERE device_id = $2
|
|
||||||
AND deleted_at IS NULL
|
|
||||||
`;
|
`;
|
||||||
await pool.query(queryText, [deletedBy, id]);
|
await pool.query(queryText, [deletedBy, id]);
|
||||||
return true;
|
return true;
|
||||||
@@ -92,5 +76,4 @@ module.exports = {
|
|||||||
createDeviceDb,
|
createDeviceDb,
|
||||||
updateDeviceDb,
|
updateDeviceDb,
|
||||||
softDeleteDeviceDb,
|
softDeleteDeviceDb,
|
||||||
searchDevicesDb,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,55 +1,87 @@
|
|||||||
const pool = require("../config");
|
const pool = require("../config");
|
||||||
|
|
||||||
// Get all roles
|
// Get all roles
|
||||||
const getAllRolesDb = async () => {
|
const getAllRolesDb = async (filters = {}) => {
|
||||||
|
const { whereConditions, queryParams } = pool.buildFilterQuery([
|
||||||
|
{ column: "r.role_name", param: filters.role_name, type: "string" },
|
||||||
|
{ column: "r.role_level", param: filters.role_level, type: "number" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const whereClause = whereConditions.length ? `AND ${whereConditions.join(" AND ")}` : "";
|
||||||
|
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT *
|
SELECT
|
||||||
FROM m_roles
|
r.role_id,
|
||||||
WHERE deleted_at IS NULL
|
r.role_name,
|
||||||
ORDER BY role_id ASC
|
r.role_description,
|
||||||
|
r.role_level,
|
||||||
|
r.created_at,
|
||||||
|
r.updated_at,
|
||||||
|
r.updated_by,
|
||||||
|
r.deleted_at,
|
||||||
|
r.deleted_by
|
||||||
|
FROM m_roles r
|
||||||
|
WHERE r.deleted_at IS NULL ${whereClause}
|
||||||
|
ORDER BY r.role_id ASC
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText);
|
|
||||||
|
const result = await pool.query(queryText, queryParams);
|
||||||
return result.recordset;
|
return result.recordset;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get role by ID
|
// Get role by ID
|
||||||
const getRoleByIdDb = async (roleId) => {
|
const getRoleByIdDb = async (id) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT *
|
SELECT
|
||||||
|
role_id,
|
||||||
|
role_name,
|
||||||
|
role_description,
|
||||||
|
role_level,
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
updated_by,
|
||||||
|
deleted_at,
|
||||||
|
deleted_by
|
||||||
FROM m_roles
|
FROM m_roles
|
||||||
WHERE role_id = $1 AND deleted_at IS NULL
|
WHERE role_id = $1 AND deleted_at IS NULL
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText, [roleId]);
|
const result = await pool.query(queryText, [id]);
|
||||||
return result.recordset[0];
|
return result.recordset[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create role
|
// Create role
|
||||||
const createRoleDb = async (data) => {
|
const createRoleDb = async (data) => {
|
||||||
const { query: queryText, values } = pool.buildDynamicInsert("m_roles", data);
|
const { query, values } = pool.buildDynamicInsert("m_roles", {
|
||||||
const result = await pool.query(queryText, values);
|
...data,
|
||||||
|
created_at: new Date(),
|
||||||
|
});
|
||||||
|
const result = await pool.query(query, values);
|
||||||
return result.recordset[0]?.inserted_id || null;
|
return result.recordset[0]?.inserted_id || null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update role
|
// Update role
|
||||||
const updateRoleDb = async (roleId, data) => {
|
const updateRoleDb = async (id, data) => {
|
||||||
const { query: queryText, values } = pool.buildDynamicUpdate("m_roles", data, { role_id: roleId });
|
const { query, values } = pool.buildDynamicUpdate(
|
||||||
await pool.query(queryText, values);
|
"m_roles",
|
||||||
|
{ ...data, updated_at: new Date() },
|
||||||
|
{ role_id: id }
|
||||||
|
);
|
||||||
|
await pool.query(query, values);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Soft delete role
|
// Soft delete role
|
||||||
const deleteRoleDb = async (roleId, deletedBy) => {
|
const deleteRoleDb = async (id, deletedBy) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
UPDATE m_roles
|
UPDATE m_roles
|
||||||
SET deleted_at = GETDATE(),
|
SET deleted_at = GETDATE(),
|
||||||
deleted_by = $1
|
deleted_by = $1
|
||||||
WHERE role_id = $2
|
WHERE role_id = $2
|
||||||
`;
|
`;
|
||||||
await pool.query(queryText, [deletedBy, roleId]);
|
await pool.query(queryText, [deletedBy, id]);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getAllRolesDb,
|
getAllRolesDb,
|
||||||
getRoleByIdDb,
|
getRoleByIdDb,
|
||||||
|
|||||||
171
db/user.db.js
171
db/user.db.js
@@ -1,36 +1,33 @@
|
|||||||
const pool = require("../config");
|
const { query, buildFilterQuery, buildDynamicUpdate } = require("../config");
|
||||||
|
|
||||||
|
// Get all users
|
||||||
|
const getAllUsersDb = async (searchParams = {}) => {
|
||||||
|
const { whereConditions, queryParams } = buildFilterQuery([
|
||||||
|
{ column: "u.user_fullname", param: searchParams.fullname, type: "string" },
|
||||||
|
{ column: "u.user_name", param: searchParams.username, type: "string" },
|
||||||
|
{ column: "u.user_email", param: searchParams.email, type: "string" },
|
||||||
|
{ column: "r.role_name", param: searchParams.role, type: "string" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const whereClause = whereConditions.length
|
||||||
|
? `AND ${whereConditions.join(" AND ")}`
|
||||||
|
: "";
|
||||||
|
|
||||||
// Get all users s
|
|
||||||
const getAllUsersDb = async () => {
|
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT
|
SELECT
|
||||||
u.user_id,
|
u.user_id, u.user_fullname, u.user_name, u.user_email, u.user_phone,
|
||||||
u.user_fullname,
|
u.is_active, u.is_sa, u.is_approve, u.approved_by,
|
||||||
u.user_name,
|
|
||||||
u.user_email,
|
|
||||||
u.user_phone,
|
|
||||||
u.is_active,
|
|
||||||
u.is_sa,
|
|
||||||
u.is_approve,
|
|
||||||
u.approved_by,
|
|
||||||
approver.user_fullname AS approved_by_name,
|
approver.user_fullname AS approved_by_name,
|
||||||
u.approved_at,
|
u.approved_at, u.created_at, u.updated_at, u.deleted_at,
|
||||||
u.created_at,
|
u.updated_by, u.deleted_by,
|
||||||
u.updated_at,
|
r.role_id, r.role_name, r.role_description, r.role_level
|
||||||
u.deleted_at,
|
|
||||||
u.updated_by,
|
|
||||||
u.deleted_by,
|
|
||||||
r.role_id,
|
|
||||||
r.role_name,
|
|
||||||
r.role_description,
|
|
||||||
r.role_level
|
|
||||||
FROM m_users u
|
FROM m_users u
|
||||||
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
||||||
LEFT JOIN m_users approver ON u.approved_by = approver.user_id
|
LEFT JOIN m_users approver ON u.approved_by = approver.user_id
|
||||||
WHERE u.deleted_at IS NULL
|
WHERE u.deleted_at IS NULL ${whereClause}
|
||||||
ORDER BY u.user_id ASC
|
ORDER BY u.user_id ASC
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText);
|
const result = await query(queryText, queryParams);
|
||||||
return result.recordset;
|
return result.recordset;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,32 +35,18 @@ const getAllUsersDb = async () => {
|
|||||||
const getUserByIdDb = async (id) => {
|
const getUserByIdDb = async (id) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT
|
SELECT
|
||||||
u.user_id,
|
u.user_id, u.user_fullname, u.user_name, u.user_email, u.user_phone,
|
||||||
u.user_fullname,
|
u.is_active, u.is_sa, u.is_approve, u.approved_by,
|
||||||
u.user_name,
|
|
||||||
u.user_email,
|
|
||||||
u.user_phone,
|
|
||||||
u.is_active,
|
|
||||||
u.is_sa,
|
|
||||||
u.is_approve,
|
|
||||||
u.approved_by,
|
|
||||||
approver.user_fullname AS approved_by_name,
|
approver.user_fullname AS approved_by_name,
|
||||||
u.approved_at,
|
u.approved_at, u.created_at, u.updated_at, u.deleted_at,
|
||||||
u.created_at,
|
u.updated_by, u.deleted_by,
|
||||||
u.updated_at,
|
r.role_id, r.role_name, r.role_description, r.role_level
|
||||||
u.deleted_at,
|
|
||||||
u.updated_by,
|
|
||||||
u.deleted_by,
|
|
||||||
r.role_id,
|
|
||||||
r.role_name,
|
|
||||||
r.role_description,
|
|
||||||
r.role_level
|
|
||||||
FROM m_users u
|
FROM m_users u
|
||||||
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
||||||
LEFT JOIN m_users approver ON u.approved_by = approver.user_id
|
LEFT JOIN m_users approver ON u.approved_by = approver.user_id
|
||||||
WHERE u.user_id = $1 AND u.deleted_at IS NULL
|
WHERE u.user_id = $1 AND u.deleted_at IS NULL
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText, [id]);
|
const result = await query(queryText, [id]);
|
||||||
return result.recordset[0];
|
return result.recordset[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,24 +54,14 @@ const getUserByIdDb = async (id) => {
|
|||||||
const getUserByUserEmailDb = async (email) => {
|
const getUserByUserEmailDb = async (email) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT
|
SELECT
|
||||||
u.user_id,
|
u.user_id, u.user_fullname, u.user_name, u.user_email, u.user_phone,
|
||||||
u.user_fullname,
|
u.user_password, u.is_active, u.is_sa, u.is_approve, u.role_id,
|
||||||
u.user_name,
|
r.role_name, r.role_description, r.role_level
|
||||||
u.user_email,
|
|
||||||
u.user_phone,
|
|
||||||
u.user_password,
|
|
||||||
u.is_active,
|
|
||||||
u.is_sa,
|
|
||||||
u.is_approve,
|
|
||||||
u.role_id,
|
|
||||||
r.role_name,
|
|
||||||
r.role_description,
|
|
||||||
r.role_level
|
|
||||||
FROM m_users u
|
FROM m_users u
|
||||||
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
||||||
WHERE u.user_email = $1 AND u.deleted_at IS NULL
|
WHERE u.user_email = $1 AND u.deleted_at IS NULL
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText, [email]);
|
const result = await query(queryText, [email]);
|
||||||
return result.recordset[0];
|
return result.recordset[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -96,64 +69,61 @@ const getUserByUserEmailDb = async (email) => {
|
|||||||
const getUserByUsernameDb = async (username) => {
|
const getUserByUsernameDb = async (username) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
SELECT
|
SELECT
|
||||||
u.user_id,
|
u.user_id, u.user_fullname, u.user_name, u.user_email, u.user_phone,
|
||||||
u.user_fullname,
|
u.user_password, u.is_active, u.is_sa, u.is_approve, u.role_id,
|
||||||
u.user_name,
|
r.role_name, r.role_description, r.role_level
|
||||||
u.user_email,
|
|
||||||
u.user_phone,
|
|
||||||
u.user_password,
|
|
||||||
u.is_active,
|
|
||||||
u.is_sa,
|
|
||||||
u.is_approve,
|
|
||||||
u.role_id,
|
|
||||||
r.role_name,
|
|
||||||
r.role_description,
|
|
||||||
r.role_level
|
|
||||||
FROM m_users u
|
FROM m_users u
|
||||||
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
||||||
WHERE u.user_name = $1 AND u.deleted_at IS NULL
|
WHERE u.user_name = $1 AND u.deleted_at IS NULL
|
||||||
`;
|
`;
|
||||||
const result = await pool.query(queryText, [username]);
|
const result = await query(queryText, [username]);
|
||||||
return result.recordset[0];
|
return result.recordset[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create user
|
// Create user
|
||||||
const createUserDb = async (data) => {
|
const createUserDb = async (data) => {
|
||||||
const { query: queryText, values } = pool.buildDynamicInsert("m_users", data);
|
const queryText = `
|
||||||
const result = await pool.query(queryText, values);
|
INSERT INTO m_users
|
||||||
return result.recordset[0]?.inserted_id || null;
|
(user_fullname, user_name, user_email, user_phone, user_password, role_id, is_sa, is_active, is_approve, approved_by, approved_at)
|
||||||
|
VALUES
|
||||||
|
($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);
|
||||||
|
SELECT SCOPE_IDENTITY() as user_id;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const values = [
|
||||||
|
data.user_fullname,
|
||||||
|
data.user_name,
|
||||||
|
data.user_email,
|
||||||
|
data.user_phone,
|
||||||
|
data.user_password,
|
||||||
|
data.role_id || null,
|
||||||
|
data.is_sa || 0,
|
||||||
|
data.is_active || 1,
|
||||||
|
data.is_approve || 0,
|
||||||
|
data.approved_by || null,
|
||||||
|
data.approved_at || null
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = await query(queryText, values);
|
||||||
|
return result.recordset[0]?.user_id || null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update user
|
// Update user
|
||||||
const updateUserDb = async (userId, data) => {
|
const updateUserDb = async (userId, data) => {
|
||||||
const { query: queryText, values } = pool.buildDynamicUpdate("m_users", data, { user_id: userId });
|
const { query: queryText, values } = buildDynamicUpdate("m_users", data, { user_id: userId });
|
||||||
await pool.query(queryText, values);
|
const finalQuery = queryText.replace("WHERE", "WHERE deleted_at IS NULL AND");
|
||||||
|
await query(finalQuery, values);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Approve user
|
// Change user password
|
||||||
const approveUserDb = async (userId, approverId) => {
|
|
||||||
const queryText = `
|
|
||||||
UPDATE m_users
|
|
||||||
SET is_approve = 1,
|
|
||||||
approved_by = $1,
|
|
||||||
approved_at = GETDATE(),
|
|
||||||
updated_at = GETDATE()
|
|
||||||
WHERE user_id = $2 AND deleted_at IS NULL
|
|
||||||
`;
|
|
||||||
await pool.query(queryText, [approverId, userId]);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Change password
|
|
||||||
const changeUserPasswordDb = async (userId, newPassword) => {
|
const changeUserPasswordDb = async (userId, newPassword) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
UPDATE m_users
|
UPDATE m_users
|
||||||
SET user_password = $1,
|
SET user_password = $1, updated_at = GETDATE()
|
||||||
updated_at = GETDATE()
|
|
||||||
WHERE user_id = $2 AND deleted_at IS NULL
|
WHERE user_id = $2 AND deleted_at IS NULL
|
||||||
`;
|
`;
|
||||||
await pool.query(queryText, [newPassword, userId]);
|
await query(queryText, [newPassword, userId]);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,11 +131,15 @@ const changeUserPasswordDb = async (userId, newPassword) => {
|
|||||||
const deleteUserDb = async (userId, deletedBy) => {
|
const deleteUserDb = async (userId, deletedBy) => {
|
||||||
const queryText = `
|
const queryText = `
|
||||||
UPDATE m_users
|
UPDATE m_users
|
||||||
SET deleted_at = GETDATE(),
|
SET
|
||||||
deleted_by = $1
|
deleted_at = GETDATE(),
|
||||||
|
deleted_by = $1,
|
||||||
|
is_active = 0
|
||||||
WHERE user_id = $2
|
WHERE user_id = $2
|
||||||
|
AND deleted_at IS NULL
|
||||||
`;
|
`;
|
||||||
await pool.query(queryText, [deletedBy, userId]);
|
|
||||||
|
await query(queryText, [deletedBy, userId]);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -176,7 +150,6 @@ module.exports = {
|
|||||||
getUserByUsernameDb,
|
getUserByUsernameDb,
|
||||||
createUserDb,
|
createUserDb,
|
||||||
updateUserDb,
|
updateUserDb,
|
||||||
approveUserDb,
|
|
||||||
changeUserPasswordDb,
|
changeUserPasswordDb,
|
||||||
deleteUserDb,
|
deleteUserDb,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -63,9 +63,38 @@ const deviceUpdateSchema = Joi.object({
|
|||||||
})
|
})
|
||||||
}).min(1);
|
}).min(1);
|
||||||
|
|
||||||
|
// ========================
|
||||||
|
// Users Validation
|
||||||
|
// ========================
|
||||||
|
const userSchema = Joi.object({
|
||||||
|
fullname: Joi.string().min(3).max(100).required(),
|
||||||
|
name: Joi.string().alphanum().min(3).max(50).required(),
|
||||||
|
email: Joi.string().email().required(),
|
||||||
|
phone: Joi.string()
|
||||||
|
.pattern(/^(?:\+62|0)8\d{7,10}$/)
|
||||||
|
.required()
|
||||||
|
.messages({
|
||||||
|
'string.pattern.base':
|
||||||
|
'Phone number must be a valid Indonesian number in format +628XXXXXXXXX'
|
||||||
|
}),
|
||||||
|
password: Joi.string()
|
||||||
|
.min(8)
|
||||||
|
.pattern(/[A-Z]/, 'uppercase letter')
|
||||||
|
.pattern(/[a-z]/, 'lowercase letter')
|
||||||
|
.pattern(/\d/, 'number')
|
||||||
|
.pattern(/[!@#$%^&*(),.?":{}|<>]/, 'special character')
|
||||||
|
.required()
|
||||||
|
.messages({
|
||||||
|
'string.min': 'Password must be at least 8 characters long',
|
||||||
|
'string.pattern.name': 'Password must contain at least one {#name}'
|
||||||
|
}),
|
||||||
|
role_id : Joi.number().integer().min(1)
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
registerSchema,
|
registerSchema,
|
||||||
loginSchema,
|
loginSchema,
|
||||||
deviceSchema,
|
deviceSchema,
|
||||||
deviceUpdateSchema
|
deviceUpdateSchema,
|
||||||
|
userSchema,
|
||||||
};
|
};
|
||||||
|
|||||||
42
middleware/verifyAcces.js
Normal file
42
middleware/verifyAcces.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
const { ErrorHandler } = require("../helpers/error");
|
||||||
|
const { getUserByIdDb } = require("../db/user.db");
|
||||||
|
|
||||||
|
const verifyAccess = (minLevel = 1, allowUnapprovedReadOnly = false) => {
|
||||||
|
return async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const user = req.user;
|
||||||
|
|
||||||
|
if (!user) throw new ErrorHandler(401, "Unauthorized: User not found");
|
||||||
|
|
||||||
|
// Super Admin bypass semua
|
||||||
|
if (user.is_sa) return next();
|
||||||
|
|
||||||
|
// Ambil user lengkap dari DB
|
||||||
|
const fullUser = await getUserByIdDb(user.user_id);
|
||||||
|
if (!fullUser) throw new ErrorHandler(403, "Forbidden: User not found");
|
||||||
|
|
||||||
|
// Jika belum di-approve
|
||||||
|
if (!fullUser.is_approve) {
|
||||||
|
// Hanya boleh GET (read-only)
|
||||||
|
if (req.method !== "GET") {
|
||||||
|
throw new ErrorHandler(403, "Account not approved — read-only access");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowUnapprovedReadOnly) return next();
|
||||||
|
|
||||||
|
throw new ErrorHandler(403, "Account not approved");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cek role level
|
||||||
|
if (!fullUser.role_level || fullUser.role_level < minLevel) {
|
||||||
|
throw new ErrorHandler(403, "Forbidden: Insufficient role level");
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = verifyAccess;
|
||||||
38
middleware/verifyAccess.js
Normal file
38
middleware/verifyAccess.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
const { ErrorHandler } = require("../helpers/error");
|
||||||
|
const { getUserByIdDb } = require("../db/user.db");
|
||||||
|
|
||||||
|
const verifyAccess = (minLevel = 1, allowUnapprovedReadOnly = false) => {
|
||||||
|
return async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const user = req.user;
|
||||||
|
|
||||||
|
if (!user) throw new ErrorHandler(401, "Unauthorized: User not found");
|
||||||
|
|
||||||
|
// Super Admin bypass semua
|
||||||
|
if (user.is_sa) return next();
|
||||||
|
|
||||||
|
const fullUser = await getUserByIdDb(user.user_id);
|
||||||
|
if (!fullUser) throw new ErrorHandler(403, "Forbidden: User not found");
|
||||||
|
|
||||||
|
if (!fullUser.is_approve) {
|
||||||
|
if (req.method !== "GET") {
|
||||||
|
throw new ErrorHandler(403, "Account not approved — read-only access");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowUnapprovedReadOnly) return next();
|
||||||
|
|
||||||
|
throw new ErrorHandler(403, "Account not approved");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fullUser.role_level || fullUser.role_level < minLevel) {
|
||||||
|
throw new ErrorHandler(403, "Forbidden: Insufficient role level");
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = verifyAccess;
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
const { ErrorHandler } = require("../helpers/error");
|
|
||||||
|
|
||||||
const verifyRole = (allowedRoles) => {
|
|
||||||
return (req, res, next) => {
|
|
||||||
try {
|
|
||||||
const user = req.user;
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
throw new ErrorHandler(401, "Unauthorized: User not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Super Admin bypass semua role
|
|
||||||
if (user.is_sa) {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allowedRoles.includes(user.role_id)) {
|
|
||||||
throw new ErrorHandler(403, "Forbidden: Access denied");
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
} catch (err) {
|
|
||||||
next(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = verifyRole;
|
|
||||||
@@ -26,7 +26,9 @@ function verifyAccessToken(req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const decoded = JWTService.verifyToken(token);
|
const decoded = JWTService.verifyToken(token);
|
||||||
setUser(req, decoded);
|
|
||||||
|
req.user = decoded;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.name === 'TokenExpiredError') {
|
if (error.name === 'TokenExpiredError') {
|
||||||
@@ -41,23 +43,6 @@ function verifyAccessToken(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyRefreshToken(req, res, next) {
|
|
||||||
try {
|
|
||||||
const refreshToken = req.cookies?.refreshToken;
|
|
||||||
|
|
||||||
if (!refreshToken) {
|
|
||||||
throw new ErrorHandler(401, 'Refresh Token is required');
|
|
||||||
}
|
|
||||||
|
|
||||||
const decoded = JWTService.verifyRefreshToken(refreshToken);
|
|
||||||
req.user = decoded;
|
|
||||||
next();
|
|
||||||
} catch (error) {
|
|
||||||
next(new ErrorHandler(401, 'Refresh token is invalid or expired'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
verifyAccessToken,
|
verifyAccessToken
|
||||||
verifyRefreshToken,
|
|
||||||
};
|
};
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const DeviceController = require('../controllers/device.controller');
|
const DeviceController = require('../controllers/device.controller');
|
||||||
const verifyToken = require("../middleware/verifyToken")
|
const verifyToken = require("../middleware/verifyToken")
|
||||||
const verifyRole = require("../middleware/verifyRole")
|
const verifyAccess = require("../middleware/verifyAcces")
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get('/', verifyToken.verifyAccessToken, DeviceController.getAll);
|
router.get('/', verifyToken.verifyAccessToken, DeviceController.getAll);
|
||||||
router.get('/:id', verifyToken.verifyAccessToken, DeviceController.getById);
|
router.get('/:id', verifyToken.verifyAccessToken, DeviceController.getById);
|
||||||
router.post('/', verifyToken.verifyAccessToken, verifyRole([1]), DeviceController.create);
|
router.post('/', verifyToken.verifyAccessToken, verifyAccess, DeviceController.create);
|
||||||
router.put('/:id', verifyToken.verifyAccessToken, verifyRole([1, 2]), DeviceController.update);
|
router.put('/:id', verifyToken.verifyAccessToken, verifyAccess, DeviceController.update);
|
||||||
router.delete('/:id', verifyToken.verifyAccessToken, verifyRole([1]), DeviceController.delete);
|
router.delete('/:id', verifyToken.verifyAccessToken, verifyAccess, DeviceController.delete);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
@@ -1,32 +1,30 @@
|
|||||||
const {
|
const express = require('express');
|
||||||
getAllUsers,
|
const UserController = require('../controllers/users.controller');
|
||||||
createUser,
|
const verifyToken = require('../middleware/verifyToken');
|
||||||
deleteUser,
|
const verifyAccess = require('../middleware/verifyAcces');
|
||||||
getUserById,
|
|
||||||
updateUser,
|
|
||||||
getUserProfile,
|
|
||||||
getAllRoles,
|
|
||||||
getAllStatusUsers
|
|
||||||
} = require("../controllers/users.controller");
|
|
||||||
const router = require("express").Router();
|
|
||||||
const verifyAdmin = require("../middleware/verifyRole");
|
|
||||||
const verifyToken = require("../middleware/verifyToken");
|
|
||||||
|
|
||||||
router.get("/roles", getAllRoles);
|
const router = express.Router();
|
||||||
|
|
||||||
router.get('/profile', verifyToken.verifyAccessToken, getUserProfile);
|
// Get all users
|
||||||
|
router.get('/', verifyToken.verifyAccessToken, UserController.getAllUsers);
|
||||||
|
|
||||||
router.route("/")
|
// Get user by ID
|
||||||
.get(verifyToken.verifyAccessToken, getAllUsers)
|
router.get('/:id', verifyToken.verifyAccessToken, UserController.getUserById);
|
||||||
.post(verifyToken.verifyAccessToken, createUser);
|
|
||||||
|
|
||||||
router
|
// Create new user
|
||||||
.route("/status")
|
router.post('/', verifyToken.verifyAccessToken, verifyAccess(), UserController.createUser);
|
||||||
.get(verifyToken.verifyAccessToken, getAllStatusUsers);
|
|
||||||
|
// Update user
|
||||||
|
router.put('/:id', verifyToken.verifyAccessToken, verifyAccess(), UserController.updateUser);
|
||||||
|
|
||||||
|
// Delete user
|
||||||
|
router.delete('/:id', verifyToken.verifyAccessToken, verifyAccess(), UserController.deleteUser);
|
||||||
|
|
||||||
|
// Change user password
|
||||||
|
router.put('/change-password/:id', verifyToken.verifyAccessToken, verifyAccess(), UserController.changePassword);
|
||||||
|
|
||||||
|
// Approve user
|
||||||
|
router.put('/:id/approve', verifyToken.verifyAccessToken, verifyAccess(), UserController.approveUser);
|
||||||
|
|
||||||
router.route("/:id")
|
|
||||||
.get(verifyToken.verifyAccessToken, getUserById)
|
|
||||||
.put(verifyToken.verifyAccessToken, updateUser)
|
|
||||||
.delete(verifyToken.verifyAccessToken, deleteUser);
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -23,9 +23,12 @@ class AuthService {
|
|||||||
user_email: email,
|
user_email: email,
|
||||||
user_phone: phone,
|
user_phone: phone,
|
||||||
user_password: hashedPassword,
|
user_password: hashedPassword,
|
||||||
role_id: 3,
|
role_id: null,
|
||||||
is_sa: 0,
|
is_sa: 0,
|
||||||
is_active: 1
|
is_active: 1,
|
||||||
|
is_approve: 0,
|
||||||
|
approved_by: null,
|
||||||
|
approved_at: null
|
||||||
});
|
});
|
||||||
|
|
||||||
const newUser = {
|
const newUser = {
|
||||||
@@ -33,8 +36,7 @@ class AuthService {
|
|||||||
user_fullname: fullname,
|
user_fullname: fullname,
|
||||||
user_name: name,
|
user_name: name,
|
||||||
user_email: email,
|
user_email: email,
|
||||||
user_phone: phone,
|
user_phone: phone
|
||||||
role_id: 3,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// generate token pair
|
// generate token pair
|
||||||
@@ -59,6 +61,10 @@ class AuthService {
|
|||||||
throw new ErrorHandler(403, 'User is inactive');
|
throw new ErrorHandler(403, 'User is inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!user.is_approve) {
|
||||||
|
throw new ErrorHandler(403, 'Your account has not been approved by admin yet.');
|
||||||
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
user_id: user.user_id,
|
user_id: user.user_id,
|
||||||
user_fullname: user.user_fullname,
|
user_fullname: user.user_fullname,
|
||||||
|
|||||||
@@ -28,9 +28,7 @@ class DeviceService {
|
|||||||
// Get device by code
|
// Get device by code
|
||||||
static async getDeviceByCode(code) {
|
static async getDeviceByCode(code) {
|
||||||
const device = await getDeviceByCodeDb(code);
|
const device = await getDeviceByCodeDb(code);
|
||||||
if (!device) {
|
if (!device) throw new ErrorHandler(404, 'Device not found');
|
||||||
throw new ErrorHandler(404, 'Device not found');
|
|
||||||
}
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +38,7 @@ class DeviceService {
|
|||||||
|
|
||||||
data.created_by = userId;
|
data.created_by = userId;
|
||||||
|
|
||||||
// cek kode unik
|
// Cek kode unik
|
||||||
const existingDevice = await getDeviceByCodeDb(data.device_code);
|
const existingDevice = await getDeviceByCodeDb(data.device_code);
|
||||||
if (existingDevice) {
|
if (existingDevice) {
|
||||||
throw new ErrorHandler(400, 'Device code already exists');
|
throw new ErrorHandler(400, 'Device code already exists');
|
||||||
@@ -61,14 +59,12 @@ class DeviceService {
|
|||||||
|
|
||||||
data.updated_by = userId;
|
data.updated_by = userId;
|
||||||
|
|
||||||
const updatedDevice = await updateDeviceDb(id, data);
|
const updatedDevice = await updateDeviceDb(id, data);
|
||||||
|
|
||||||
|
|
||||||
await updateDeviceDb(id, data);
|
|
||||||
return {
|
return {
|
||||||
message: 'Device updated successfully',
|
message: 'Device updated successfully',
|
||||||
data: updatedDevice,
|
data: updatedDevice,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Soft delete device
|
// Soft delete device
|
||||||
|
|||||||
@@ -1,122 +1,174 @@
|
|||||||
const {
|
const {
|
||||||
createUserDb,
|
createUserDb,
|
||||||
changeUserPasswordDb,
|
|
||||||
getUserByIdDb,
|
getUserByIdDb,
|
||||||
updateUserDb,
|
|
||||||
deleteUserDb,
|
|
||||||
getAllUsersDb,
|
getAllUsersDb,
|
||||||
getUserByUsernameDb,
|
getUserByUsernameDb,
|
||||||
getAllRoleDb
|
updateUserDb,
|
||||||
} = require("../db/user.db");
|
deleteUserDb,
|
||||||
const { ErrorHandler } = require("../helpers/error");
|
changeUserPasswordDb
|
||||||
const { convertId } = require("../helpers/utils");
|
} = require('../db/user.db');
|
||||||
|
const { hashPassword } = require('../helpers/hashPassword');
|
||||||
|
const { ErrorHandler } = require('../helpers/error');
|
||||||
|
|
||||||
const statusName = [
|
const statusName = [
|
||||||
{
|
{ status: true, status_name: "Aktif" },
|
||||||
status: true,
|
{ status: false, status_name: "NonAktif" }
|
||||||
status_name: "Aktif"
|
|
||||||
}, {
|
|
||||||
status: false,
|
|
||||||
status_name: "NonAktif"
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
class UserService {
|
class UserService {
|
||||||
|
|
||||||
|
// Get all status users
|
||||||
getAllStatusUsers = async () => {
|
getAllStatusUsers = async () => {
|
||||||
try {
|
try {
|
||||||
return statusName;
|
return statusName;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ErrorHandler(error.statusCode, error.message);
|
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getAllUsers = async (param) => {
|
// Get all users
|
||||||
|
getAllUsers = async () => {
|
||||||
try {
|
try {
|
||||||
const results = await getAllUsersDb(param);
|
const results = await getAllUsersDb();
|
||||||
|
|
||||||
results.data.map(element => {
|
results.forEach(user => {
|
||||||
element.is_active = element.is_active == 1 ? true : false
|
user.is_active = user.is_active == 1;
|
||||||
element.is_active_name = convertId(statusName, element.is_active, 'status', 'status_name')
|
user.is_active_name = statusName.find(s => s.status === user.is_active)?.status_name;
|
||||||
|
delete user.user_password; // remove password
|
||||||
});
|
});
|
||||||
|
|
||||||
return results
|
return results;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ErrorHandler(error.statusCode, error.message);
|
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
createUser = async (param) => {
|
|
||||||
try {
|
|
||||||
const userByUsername = await getUserByUsernameDb(param.userName, param.tenantID);
|
|
||||||
|
|
||||||
if (userByUsername) {
|
|
||||||
throw new ErrorHandler(401, "username taken already");
|
|
||||||
}
|
|
||||||
|
|
||||||
return await createUserDb(param);
|
|
||||||
} catch (error) {
|
|
||||||
throw new ErrorHandler(error.statusCode, error.message);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Get user by ID
|
||||||
getUserById = async (id) => {
|
getUserById = async (id) => {
|
||||||
try {
|
try {
|
||||||
const user = await getUserByIdDb(id);
|
const user = await getUserByIdDb(id);
|
||||||
// user.password = undefined;
|
if (!user) throw new ErrorHandler(404, "User not found");
|
||||||
user.is_active = user.is_active == 1 ? true : false
|
|
||||||
|
user.is_active = user.is_active == 1;
|
||||||
|
user.is_active_name = statusName.find(s => s.status === user.is_active)?.status_name;
|
||||||
|
delete user.user_password;
|
||||||
return user;
|
return user;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ErrorHandler(error.statusCode, error.message);
|
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
changeUserPassword = async (password, email, tenantID) => {
|
// Create users
|
||||||
|
createUser = async ({ fullname, name, email, phone, password, role_id = null, is_sa = 0, is_active = 1, approved_by }) => {
|
||||||
try {
|
try {
|
||||||
return await changeUserPasswordDb(password, email, tenantID);
|
const existingUser = await getUserByUsernameDb(name);
|
||||||
|
if (existingUser) throw new ErrorHandler(400, "Username already taken");
|
||||||
|
|
||||||
|
const hashedPassword = await hashPassword(password);
|
||||||
|
|
||||||
|
const userId = await createUserDb({
|
||||||
|
user_fullname: fullname,
|
||||||
|
user_name: name,
|
||||||
|
user_email: email,
|
||||||
|
user_phone: phone,
|
||||||
|
user_password: hashedPassword,
|
||||||
|
role_id,
|
||||||
|
is_sa,
|
||||||
|
is_active,
|
||||||
|
is_approve: 1,
|
||||||
|
approved_by,
|
||||||
|
approved_at: new Date()
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
user_id: userId,
|
||||||
|
user_fullname: fullname,
|
||||||
|
user_name: name,
|
||||||
|
user_email: email,
|
||||||
|
user_phone: phone,
|
||||||
|
role_id,
|
||||||
|
is_sa,
|
||||||
|
is_active,
|
||||||
|
is_approve: 1,
|
||||||
|
approved_by
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ErrorHandler(error.statusCode, error.message);
|
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateUser = async (param) => {
|
// Update user
|
||||||
const { userName, id } = param;
|
updateUser = async ({ user_id, fullname, name, email, phone, role_id, is_sa, is_active, is_approve }) => {
|
||||||
const errors = {};
|
|
||||||
try {
|
try {
|
||||||
|
const user = await getUserByIdDb(user_id);
|
||||||
|
if (!user) throw new ErrorHandler(404, "User not found");
|
||||||
|
|
||||||
const user = await getUserByIdDb(id);
|
// Cek username
|
||||||
|
if (name && user.user_name.toLowerCase() !== name.toLowerCase()) {
|
||||||
const findUserByUsername = await getUserByUsernameDb(userName, param.tenantID);
|
const userByName = await getUserByUsernameDb(name);
|
||||||
|
if (userByName) throw new ErrorHandler(400, "Username already taken");
|
||||||
const usernameChanged = userName && user.user_name.toLowerCase() !== userName.toLowerCase();
|
|
||||||
|
|
||||||
if (usernameChanged && typeof findUserByUsername === "object") {
|
|
||||||
errors["username"] = "Username is already taken";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(errors).length > 0) {
|
const updateData = {
|
||||||
throw new ErrorHandler(403, errors);
|
...(fullname && { user_fullname: fullname }),
|
||||||
}
|
...(name && { user_name: name }),
|
||||||
|
...(email && { user_email: email }),
|
||||||
|
...(phone && { user_phone: phone }),
|
||||||
|
...(role_id !== undefined && { role_id }),
|
||||||
|
...(is_sa !== undefined && { is_sa }),
|
||||||
|
...(is_active !== undefined && { is_active }),
|
||||||
|
...(is_approve !== undefined && { is_approve })
|
||||||
|
};
|
||||||
|
|
||||||
return await updateUserDb(param);
|
await updateUserDb(user_id, updateData);
|
||||||
|
|
||||||
|
const updatedUser = await getUserByIdDb(user_id);
|
||||||
|
delete updatedUser.user_password;
|
||||||
|
updatedUser.is_active = updatedUser.is_active == 1;
|
||||||
|
updatedUser.is_active_name = statusName.find(s => s.status === updatedUser.is_active)?.status_name;
|
||||||
|
|
||||||
|
return updatedUser;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ErrorHandler(error.statusCode, error.message);
|
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
deleteUser = async (id, userID) => {
|
// Approve user
|
||||||
|
approveUser = async (userId, approverId) => {
|
||||||
try {
|
try {
|
||||||
return await deleteUserDb(id, userID);
|
const updateData = {
|
||||||
|
is_approve: 1,
|
||||||
|
approved_by: approverId,
|
||||||
|
approved_at: new Date()
|
||||||
|
};
|
||||||
|
await updateUserDb(userId, updateData);
|
||||||
|
|
||||||
|
const updatedUser = await getUserByIdDb(userId);
|
||||||
|
delete updatedUser.user_password;
|
||||||
|
return updatedUser;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ErrorHandler(error.statusCode, error.message);
|
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getAllRoles = async (tenantID) => {
|
// Delete user (soft delete)
|
||||||
|
deleteUser = async (userId, deletedBy) => {
|
||||||
try {
|
try {
|
||||||
return await getAllRoleDb(tenantID);
|
await deleteUserDb(userId, deletedBy);
|
||||||
|
return { message: "User deleted successfully" };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new ErrorHandler(error.statusCode, error.message);
|
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Change password
|
||||||
|
changeUserPassword = async (userId, newPassword) => {
|
||||||
|
try {
|
||||||
|
const hashedPassword = await hashPassword(newPassword);
|
||||||
|
await changeUserPasswordDb(userId, hashedPassword);
|
||||||
|
return { message: "Password updated successfully" };
|
||||||
|
} catch (error) {
|
||||||
|
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user