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);
|
||||
|
||||
// Set refresh token in cookie
|
||||
// Set refresh token di cookie
|
||||
res.cookie('refreshToken', tokens.refreshToken, {
|
||||
httpOnly: true,
|
||||
secure: false, //masih dev
|
||||
secure: false, // masih dev
|
||||
sameSite: 'lax',
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 hari
|
||||
});
|
||||
|
||||
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) {
|
||||
return res.status(err.statusCode || 500).json(
|
||||
@@ -68,7 +75,7 @@ class AuthController {
|
||||
|
||||
const { user, tokens } = await AuthService.login({ email, password });
|
||||
|
||||
// Set refresh token in cookie
|
||||
// Set refresh token di cookie
|
||||
res.cookie('refreshToken', tokens.refreshToken, {
|
||||
httpOnly: true,
|
||||
secure: false, // masih dev
|
||||
@@ -77,7 +84,14 @@ class AuthController {
|
||||
});
|
||||
|
||||
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) {
|
||||
return res.status(err.statusCode || 500).json(
|
||||
|
||||
@@ -1,172 +1,157 @@
|
||||
const userService = require("../services/user.service");
|
||||
const { ErrorHandler } = require("../helpers/error");
|
||||
const { hashPassword } = require("../helpers/hashPassword");
|
||||
const { setResponse, setPaging, setResponsePaging } = require("../helpers/utils");
|
||||
const { setResponse } = require("../helpers/utils");
|
||||
const Joi = require("joi");
|
||||
const { userSchema } = require("../helpers/validation");
|
||||
|
||||
// Definisikan skema validasi
|
||||
const validateTerm = Joi.object({
|
||||
user_fullname: Joi.string().max(255).required(),
|
||||
user_name: Joi.string().max(255).required(),
|
||||
user_email: Joi.string().max(255).email().allow(null),
|
||||
user_password: Joi.string().max(255).required(),
|
||||
role_id: Joi.number().integer().allow(null),
|
||||
is_active: Joi.boolean().required()
|
||||
});
|
||||
|
||||
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'
|
||||
]
|
||||
class UserController {
|
||||
// Get all users
|
||||
static async getAllUsers(req, res) {
|
||||
try {
|
||||
const users = await userService.getAllUsers();
|
||||
return res.status(200).json(setResponse(users, "Users retrieved successfully", 200));
|
||||
} catch (error) {
|
||||
return res
|
||||
.status(error.statusCode || 500)
|
||||
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||
}
|
||||
}
|
||||
|
||||
const results = await userService.getAllUsers(filterQuery)
|
||||
const response = await setResponsePaging(results.data, results.total, parseInt(limit), parseInt(page))
|
||||
|
||||
res.status(response.statusCode).json(response)
|
||||
};
|
||||
|
||||
const getAllStatusUsers = async (req, res) => {
|
||||
|
||||
const results = await userService.getAllStatusUsers();
|
||||
const response = await setResponse(results)
|
||||
|
||||
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);
|
||||
// Get user by ID
|
||||
static async getUserById(req, res) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const user = await userService.getUserById(id);
|
||||
return res.status(200).json(setResponse(user, "User retrieved successfully", 200));
|
||||
} catch (error) {
|
||||
return res
|
||||
.status(error.statusCode || 500)
|
||||
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||
}
|
||||
}
|
||||
|
||||
const results = await userService.createUser({
|
||||
userFullname: req.body.user_fullname,
|
||||
userName: req.body.user_name,
|
||||
userEmail: req.body.user_email,
|
||||
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
|
||||
});
|
||||
// Create new user
|
||||
static async createUser(req, res) {
|
||||
try {
|
||||
const { error, value } = userSchema.validate(req.body, { abortEarly: false });
|
||||
|
||||
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) => {
|
||||
const { id } = req.params;
|
||||
|
||||
const results = await userService.getUserById(id);
|
||||
const response = await setResponse(results)
|
||||
|
||||
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);
|
||||
return res.status(201).json(setResponse(result, "User created successfully", 201));
|
||||
} catch (error) {
|
||||
return res
|
||||
.status(error.statusCode || 500)
|
||||
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||
}
|
||||
}
|
||||
|
||||
const results = await userService.updateUser({
|
||||
userFullname: req.body.user_fullname,
|
||||
userName: req.body.user_name,
|
||||
userEmail: req.body.user_email,
|
||||
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,
|
||||
id
|
||||
});
|
||||
// Update user
|
||||
static async updateUser(req, res) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
fullname,
|
||||
name,
|
||||
email,
|
||||
phone,
|
||||
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) => {
|
||||
const { id } = req.params;
|
||||
const userID = req.userID
|
||||
return res.status(200).json(setResponse(result, "User updated successfully", 200));
|
||||
} catch (error) {
|
||||
return res
|
||||
.status(error.statusCode || 500)
|
||||
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||
}
|
||||
}
|
||||
|
||||
const results = await userService.deleteUser(id, userID);
|
||||
const response = await setResponse(results)
|
||||
// Delete user
|
||||
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) => {
|
||||
const results = await userService.getAllRoles(req.body.tenantID);
|
||||
const response = await setResponse(results)
|
||||
// Change user password
|
||||
static async changePassword(req, res) {
|
||||
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 = {
|
||||
getAllUsers,
|
||||
createUser,
|
||||
getUserById,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
getUserProfile,
|
||||
getAllRoles,
|
||||
getAllStatusUsers
|
||||
};
|
||||
const result = await userService.changeUserPassword(user_id, new_password);
|
||||
return res.status(200).json(setResponse(result, "Password changed successfully", 200));
|
||||
} catch (error) {
|
||||
return res
|
||||
.status(error.statusCode || 500)
|
||||
.json(setResponse(null, error.message, error.statusCode || 500));
|
||||
}
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
||||
// 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 = `
|
||||
SELECT *
|
||||
FROM m_brands
|
||||
WHERE deleted_at IS NULL
|
||||
ORDER BY brand_id ASC
|
||||
SELECT
|
||||
b.brand_id,
|
||||
b.brand_name,
|
||||
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;
|
||||
};
|
||||
|
||||
// Get brand by ID
|
||||
const getBrandByIdDb = async (id) => {
|
||||
const queryText = `
|
||||
SELECT *
|
||||
SELECT
|
||||
brand_id,
|
||||
brand_name,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at,
|
||||
created_by,
|
||||
updated_by,
|
||||
deleted_by
|
||||
FROM m_brands
|
||||
WHERE brand_id = $1
|
||||
AND deleted_at IS NULL
|
||||
WHERE brand_id = $1 AND deleted_at IS NULL
|
||||
`;
|
||||
const result = await pool.query(queryText, [id]);
|
||||
return result.recordset[0];
|
||||
@@ -27,10 +49,17 @@ const getBrandByIdDb = async (id) => {
|
||||
// Get brand by name
|
||||
const getBrandByNameDb = async (name) => {
|
||||
const queryText = `
|
||||
SELECT *
|
||||
SELECT
|
||||
brand_id,
|
||||
brand_name,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at,
|
||||
created_by,
|
||||
updated_by,
|
||||
deleted_by
|
||||
FROM m_brands
|
||||
WHERE brand_name = $1
|
||||
AND deleted_at IS NULL
|
||||
WHERE brand_name = $1 AND deleted_at IS NULL
|
||||
`;
|
||||
const result = await pool.query(queryText, [name]);
|
||||
return result.recordset[0];
|
||||
@@ -38,18 +67,24 @@ const getBrandByNameDb = async (name) => {
|
||||
|
||||
// Create brand
|
||||
const createBrandDb = async (data) => {
|
||||
const { query: queryText, values } = pool.buildDynamicInsert("m_brands", data);
|
||||
const result = await pool.query(queryText, values);
|
||||
const { query, values } = pool.buildDynamicInsert("m_brands", {
|
||||
...data,
|
||||
created_at: new Date(),
|
||||
});
|
||||
const result = await pool.query(query, values);
|
||||
const insertedId = result.recordset[0]?.inserted_id;
|
||||
if (!insertedId) return null;
|
||||
|
||||
return getBrandByIdDb(insertedId);
|
||||
};
|
||||
|
||||
// Update brand
|
||||
const updateBrandDb = async (id, data) => {
|
||||
const { query: queryText, values } = pool.buildDynamicUpdate("m_brands", data, { brand_id: id });
|
||||
await pool.query(queryText, values);
|
||||
const { query, values } = pool.buildDynamicUpdate(
|
||||
"m_brands",
|
||||
{ ...data, updated_at: new Date() },
|
||||
{ brand_id: id }
|
||||
);
|
||||
await pool.query(query, values);
|
||||
return getBrandByIdDb(id);
|
||||
};
|
||||
|
||||
@@ -59,8 +94,7 @@ const softDeleteBrandDb = async (id, deletedBy) => {
|
||||
UPDATE m_brands
|
||||
SET deleted_at = GETDATE(),
|
||||
deleted_by = $1
|
||||
WHERE brand_id = $2
|
||||
AND deleted_at IS NULL
|
||||
WHERE brand_id = $2 AND deleted_at IS NULL
|
||||
`;
|
||||
await pool.query(queryText, [deletedBy, id]);
|
||||
return true;
|
||||
|
||||
@@ -1,85 +1,69 @@
|
||||
const pool = require("../config");
|
||||
|
||||
// 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 = `
|
||||
SELECT *
|
||||
FROM m_device
|
||||
WHERE deleted_at IS NULL
|
||||
ORDER BY device_id ASC
|
||||
SELECT d.*, b.brand_name
|
||||
FROM m_device d
|
||||
LEFT JOIN m_brands b ON d.brand_id = b.brand_id
|
||||
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;
|
||||
};
|
||||
|
||||
// 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 queryText = `
|
||||
SELECT *
|
||||
FROM m_device
|
||||
WHERE device_id = $1
|
||||
AND deleted_at IS NULL
|
||||
SELECT d.*, b.brand_name
|
||||
FROM m_device d
|
||||
LEFT JOIN m_brands b ON d.brand_id = b.brand_id
|
||||
WHERE d.device_id = $1 AND d.deleted_at IS NULL
|
||||
`;
|
||||
const result = await pool.query(queryText, [id]);
|
||||
return result.recordset[0];
|
||||
};
|
||||
|
||||
// Get device by device_code
|
||||
const getDeviceByCodeDb = async (code) => {
|
||||
const queryText = `
|
||||
SELECT *
|
||||
FROM m_device
|
||||
WHERE device_code = $1
|
||||
AND deleted_at IS NULL
|
||||
SELECT d.*, b.brand_name
|
||||
FROM m_device d
|
||||
LEFT JOIN m_brands b ON d.brand_id = b.brand_id
|
||||
WHERE d.device_code = $1 AND d.deleted_at IS NULL
|
||||
`;
|
||||
const result = await pool.query(queryText, [code]);
|
||||
return result.recordset[0];
|
||||
};
|
||||
|
||||
// Create device
|
||||
const createDeviceDb = async (data) => {
|
||||
const { query: queryText, values } = pool.buildDynamicInsert("m_device", data);
|
||||
const result = await pool.query(queryText, values);
|
||||
const insertedId = result.recordset[0]?.inserted_id;
|
||||
if (!insertedId) return null;
|
||||
|
||||
return getDeviceByIdDb(insertedId);
|
||||
return insertedId ? await getDeviceByIdDb(insertedId) : null;
|
||||
};
|
||||
|
||||
// Update device
|
||||
const updateDeviceDb = async (id, data) => {
|
||||
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);
|
||||
};
|
||||
|
||||
// Soft delete device
|
||||
const softDeleteDeviceDb = async (id, deletedBy) => {
|
||||
const queryText = `
|
||||
UPDATE m_device
|
||||
SET deleted_at = GETDATE(),
|
||||
deleted_by = $1
|
||||
WHERE device_id = $2
|
||||
AND deleted_at IS NULL
|
||||
SET deleted_at = GETDATE(), deleted_by = $1
|
||||
WHERE device_id = $2 AND deleted_at IS NULL
|
||||
`;
|
||||
await pool.query(queryText, [deletedBy, id]);
|
||||
return true;
|
||||
@@ -92,5 +76,4 @@ module.exports = {
|
||||
createDeviceDb,
|
||||
updateDeviceDb,
|
||||
softDeleteDeviceDb,
|
||||
searchDevicesDb,
|
||||
};
|
||||
|
||||
@@ -1,59 +1,91 @@
|
||||
const pool = require("../config");
|
||||
|
||||
// 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 = `
|
||||
SELECT *
|
||||
FROM m_roles
|
||||
WHERE deleted_at IS NULL
|
||||
ORDER BY role_id ASC
|
||||
SELECT
|
||||
r.role_id,
|
||||
r.role_name,
|
||||
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;
|
||||
};
|
||||
|
||||
// Get role by ID
|
||||
const getRoleByIdDb = async (roleId) => {
|
||||
const getRoleByIdDb = async (id) => {
|
||||
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
|
||||
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];
|
||||
};
|
||||
|
||||
// Create role
|
||||
const createRoleDb = async (data) => {
|
||||
const { query: queryText, values } = pool.buildDynamicInsert("m_roles", data);
|
||||
const result = await pool.query(queryText, values);
|
||||
const { query, values } = pool.buildDynamicInsert("m_roles", {
|
||||
...data,
|
||||
created_at: new Date(),
|
||||
});
|
||||
const result = await pool.query(query, values);
|
||||
return result.recordset[0]?.inserted_id || null;
|
||||
};
|
||||
|
||||
// Update role
|
||||
const updateRoleDb = async (roleId, data) => {
|
||||
const { query: queryText, values } = pool.buildDynamicUpdate("m_roles", data, { role_id: roleId });
|
||||
await pool.query(queryText, values);
|
||||
const updateRoleDb = async (id, data) => {
|
||||
const { query, values } = pool.buildDynamicUpdate(
|
||||
"m_roles",
|
||||
{ ...data, updated_at: new Date() },
|
||||
{ role_id: id }
|
||||
);
|
||||
await pool.query(query, values);
|
||||
return true;
|
||||
};
|
||||
|
||||
// Soft delete role
|
||||
const deleteRoleDb = async (roleId, deletedBy) => {
|
||||
const deleteRoleDb = async (id, deletedBy) => {
|
||||
const queryText = `
|
||||
UPDATE m_roles
|
||||
SET deleted_at = GETDATE(),
|
||||
deleted_by = $1
|
||||
WHERE role_id = $2
|
||||
`;
|
||||
await pool.query(queryText, [deletedBy, roleId]);
|
||||
await pool.query(queryText, [deletedBy, id]);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
getAllRolesDb,
|
||||
getRoleByIdDb,
|
||||
createRoleDb,
|
||||
updateRoleDb,
|
||||
deleteRoleDb,
|
||||
};
|
||||
};
|
||||
|
||||
179
db/user.db.js
179
db/user.db.js
@@ -1,159 +1,129 @@
|
||||
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 = `
|
||||
SELECT
|
||||
u.user_id,
|
||||
u.user_fullname,
|
||||
u.user_name,
|
||||
u.user_email,
|
||||
u.user_phone,
|
||||
u.is_active,
|
||||
u.is_sa,
|
||||
u.is_approve,
|
||||
u.approved_by,
|
||||
u.user_id, u.user_fullname, 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,
|
||||
u.approved_at,
|
||||
u.created_at,
|
||||
u.updated_at,
|
||||
u.deleted_at,
|
||||
u.updated_by,
|
||||
u.deleted_by,
|
||||
r.role_id,
|
||||
r.role_name,
|
||||
r.role_description,
|
||||
r.role_level
|
||||
u.approved_at, u.created_at, u.updated_at, 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
|
||||
LEFT JOIN m_roles r ON u.role_id = r.role_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
|
||||
`;
|
||||
const result = await pool.query(queryText);
|
||||
const result = await query(queryText, queryParams);
|
||||
return result.recordset;
|
||||
};
|
||||
|
||||
// Get user by ID
|
||||
// Get user by ID
|
||||
const getUserByIdDb = async (id) => {
|
||||
const queryText = `
|
||||
SELECT
|
||||
u.user_id,
|
||||
u.user_fullname,
|
||||
u.user_name,
|
||||
u.user_email,
|
||||
u.user_phone,
|
||||
u.is_active,
|
||||
u.is_sa,
|
||||
u.is_approve,
|
||||
u.approved_by,
|
||||
u.user_id, u.user_fullname, 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,
|
||||
u.approved_at,
|
||||
u.created_at,
|
||||
u.updated_at,
|
||||
u.deleted_at,
|
||||
u.updated_by,
|
||||
u.deleted_by,
|
||||
r.role_id,
|
||||
r.role_name,
|
||||
r.role_description,
|
||||
r.role_level
|
||||
u.approved_at, u.created_at, u.updated_at, 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
|
||||
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
||||
LEFT JOIN m_users approver ON u.approved_by = approver.user_id
|
||||
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];
|
||||
};
|
||||
|
||||
// Get user by email
|
||||
// Get user by email
|
||||
const getUserByUserEmailDb = async (email) => {
|
||||
const queryText = `
|
||||
SELECT
|
||||
u.user_id,
|
||||
u.user_fullname,
|
||||
u.user_name,
|
||||
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
|
||||
u.user_id, u.user_fullname, u.user_name, 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
|
||||
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
||||
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];
|
||||
};
|
||||
|
||||
// Get user by username
|
||||
// Get user by username
|
||||
const getUserByUsernameDb = async (username) => {
|
||||
const queryText = `
|
||||
SELECT
|
||||
u.user_id,
|
||||
u.user_fullname,
|
||||
u.user_name,
|
||||
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
|
||||
u.user_id, u.user_fullname, u.user_name, 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
|
||||
LEFT JOIN m_roles r ON u.role_id = r.role_id
|
||||
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];
|
||||
};
|
||||
|
||||
// Create user
|
||||
const createUserDb = async (data) => {
|
||||
const { query: queryText, values } = pool.buildDynamicInsert("m_users", data);
|
||||
const result = await pool.query(queryText, values);
|
||||
return result.recordset[0]?.inserted_id || null;
|
||||
const queryText = `
|
||||
INSERT INTO m_users
|
||||
(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
|
||||
const updateUserDb = async (userId, data) => {
|
||||
const { query: queryText, values } = pool.buildDynamicUpdate("m_users", data, { user_id: userId });
|
||||
await pool.query(queryText, values);
|
||||
const { query: queryText, values } = buildDynamicUpdate("m_users", data, { user_id: userId });
|
||||
const finalQuery = queryText.replace("WHERE", "WHERE deleted_at IS NULL AND");
|
||||
await query(finalQuery, values);
|
||||
return true;
|
||||
};
|
||||
|
||||
// Approve user
|
||||
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
|
||||
// Change user password
|
||||
const changeUserPasswordDb = async (userId, newPassword) => {
|
||||
const queryText = `
|
||||
UPDATE m_users
|
||||
SET user_password = $1,
|
||||
updated_at = GETDATE()
|
||||
SET user_password = $1, updated_at = GETDATE()
|
||||
WHERE user_id = $2 AND deleted_at IS NULL
|
||||
`;
|
||||
await pool.query(queryText, [newPassword, userId]);
|
||||
await query(queryText, [newPassword, userId]);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -161,11 +131,15 @@ const changeUserPasswordDb = async (userId, newPassword) => {
|
||||
const deleteUserDb = async (userId, deletedBy) => {
|
||||
const queryText = `
|
||||
UPDATE m_users
|
||||
SET deleted_at = GETDATE(),
|
||||
deleted_by = $1
|
||||
WHERE user_id = $2
|
||||
SET
|
||||
deleted_at = GETDATE(),
|
||||
deleted_by = $1,
|
||||
is_active = 0
|
||||
WHERE user_id = $2
|
||||
AND deleted_at IS NULL
|
||||
`;
|
||||
await pool.query(queryText, [deletedBy, userId]);
|
||||
|
||||
await query(queryText, [deletedBy, userId]);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -176,7 +150,6 @@ module.exports = {
|
||||
getUserByUsernameDb,
|
||||
createUserDb,
|
||||
updateUserDb,
|
||||
approveUserDb,
|
||||
changeUserPasswordDb,
|
||||
deleteUserDb,
|
||||
};
|
||||
|
||||
@@ -63,9 +63,38 @@ const deviceUpdateSchema = Joi.object({
|
||||
})
|
||||
}).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 = {
|
||||
registerSchema,
|
||||
loginSchema,
|
||||
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);
|
||||
setUser(req, decoded);
|
||||
|
||||
req.user = decoded;
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
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 = {
|
||||
verifyAccessToken,
|
||||
verifyRefreshToken,
|
||||
verifyAccessToken
|
||||
};
|
||||
@@ -1,14 +1,14 @@
|
||||
const express = require('express');
|
||||
const DeviceController = require('../controllers/device.controller');
|
||||
const verifyToken = require("../middleware/verifyToken")
|
||||
const verifyRole = require("../middleware/verifyRole")
|
||||
const verifyAccess = require("../middleware/verifyAcces")
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', verifyToken.verifyAccessToken, DeviceController.getAll);
|
||||
router.get('/:id', verifyToken.verifyAccessToken, DeviceController.getById);
|
||||
router.post('/', verifyToken.verifyAccessToken, verifyRole([1]), DeviceController.create);
|
||||
router.put('/:id', verifyToken.verifyAccessToken, verifyRole([1, 2]), DeviceController.update);
|
||||
router.delete('/:id', verifyToken.verifyAccessToken, verifyRole([1]), DeviceController.delete);
|
||||
router.post('/', verifyToken.verifyAccessToken, verifyAccess, DeviceController.create);
|
||||
router.put('/:id', verifyToken.verifyAccessToken, verifyAccess, DeviceController.update);
|
||||
router.delete('/:id', verifyToken.verifyAccessToken, verifyAccess, DeviceController.delete);
|
||||
|
||||
module.exports = router;
|
||||
@@ -1,32 +1,30 @@
|
||||
const {
|
||||
getAllUsers,
|
||||
createUser,
|
||||
deleteUser,
|
||||
getUserById,
|
||||
updateUser,
|
||||
getUserProfile,
|
||||
getAllRoles,
|
||||
getAllStatusUsers
|
||||
} = require("../controllers/users.controller");
|
||||
const router = require("express").Router();
|
||||
const verifyAdmin = require("../middleware/verifyRole");
|
||||
const verifyToken = require("../middleware/verifyToken");
|
||||
const express = require('express');
|
||||
const UserController = require('../controllers/users.controller');
|
||||
const verifyToken = require('../middleware/verifyToken');
|
||||
const verifyAccess = require('../middleware/verifyAcces');
|
||||
|
||||
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(verifyToken.verifyAccessToken, getAllUsers)
|
||||
.post(verifyToken.verifyAccessToken, createUser);
|
||||
// Get user by ID
|
||||
router.get('/:id', verifyToken.verifyAccessToken, UserController.getUserById);
|
||||
|
||||
router
|
||||
.route("/status")
|
||||
.get(verifyToken.verifyAccessToken, getAllStatusUsers);
|
||||
// Create new user
|
||||
router.post('/', verifyToken.verifyAccessToken, verifyAccess(), UserController.createUser);
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -23,9 +23,12 @@ class AuthService {
|
||||
user_email: email,
|
||||
user_phone: phone,
|
||||
user_password: hashedPassword,
|
||||
role_id: 3,
|
||||
role_id: null,
|
||||
is_sa: 0,
|
||||
is_active: 1
|
||||
is_active: 1,
|
||||
is_approve: 0,
|
||||
approved_by: null,
|
||||
approved_at: null
|
||||
});
|
||||
|
||||
const newUser = {
|
||||
@@ -33,8 +36,7 @@ class AuthService {
|
||||
user_fullname: fullname,
|
||||
user_name: name,
|
||||
user_email: email,
|
||||
user_phone: phone,
|
||||
role_id: 3,
|
||||
user_phone: phone
|
||||
};
|
||||
|
||||
// generate token pair
|
||||
@@ -59,6 +61,10 @@ class AuthService {
|
||||
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 = {
|
||||
user_id: user.user_id,
|
||||
user_fullname: user.user_fullname,
|
||||
|
||||
@@ -28,9 +28,7 @@ class DeviceService {
|
||||
// Get device by code
|
||||
static async getDeviceByCode(code) {
|
||||
const device = await getDeviceByCodeDb(code);
|
||||
if (!device) {
|
||||
throw new ErrorHandler(404, 'Device not found');
|
||||
}
|
||||
if (!device) throw new ErrorHandler(404, 'Device not found');
|
||||
return device;
|
||||
}
|
||||
|
||||
@@ -40,7 +38,7 @@ class DeviceService {
|
||||
|
||||
data.created_by = userId;
|
||||
|
||||
// cek kode unik
|
||||
// Cek kode unik
|
||||
const existingDevice = await getDeviceByCodeDb(data.device_code);
|
||||
if (existingDevice) {
|
||||
throw new ErrorHandler(400, 'Device code already exists');
|
||||
@@ -61,14 +59,12 @@ class DeviceService {
|
||||
|
||||
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',
|
||||
data: updatedDevice,
|
||||
};
|
||||
data: updatedDevice,
|
||||
};
|
||||
}
|
||||
|
||||
// Soft delete device
|
||||
|
||||
@@ -1,122 +1,174 @@
|
||||
const {
|
||||
const {
|
||||
createUserDb,
|
||||
changeUserPasswordDb,
|
||||
getUserByIdDb,
|
||||
updateUserDb,
|
||||
deleteUserDb,
|
||||
getAllUsersDb,
|
||||
getUserByUsernameDb,
|
||||
getAllRoleDb
|
||||
} = require("../db/user.db");
|
||||
const { ErrorHandler } = require("../helpers/error");
|
||||
const { convertId } = require("../helpers/utils");
|
||||
updateUserDb,
|
||||
deleteUserDb,
|
||||
changeUserPasswordDb
|
||||
} = require('../db/user.db');
|
||||
const { hashPassword } = require('../helpers/hashPassword');
|
||||
const { ErrorHandler } = require('../helpers/error');
|
||||
|
||||
const statusName = [
|
||||
{
|
||||
status: true,
|
||||
status_name: "Aktif"
|
||||
}, {
|
||||
status: false,
|
||||
status_name: "NonAktif"
|
||||
}
|
||||
{ status: true, status_name: "Aktif" },
|
||||
{ status: false, status_name: "NonAktif" }
|
||||
];
|
||||
|
||||
class UserService {
|
||||
|
||||
// Get all status users
|
||||
getAllStatusUsers = async () => {
|
||||
try {
|
||||
return statusName;
|
||||
} 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 {
|
||||
const results = await getAllUsersDb(param);
|
||||
const results = await getAllUsersDb();
|
||||
|
||||
results.data.map(element => {
|
||||
element.is_active = element.is_active == 1 ? true : false
|
||||
element.is_active_name = convertId(statusName, element.is_active, 'status', 'status_name')
|
||||
results.forEach(user => {
|
||||
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; // remove password
|
||||
});
|
||||
|
||||
return results
|
||||
return results;
|
||||
} catch (error) {
|
||||
throw new ErrorHandler(error.statusCode, 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);
|
||||
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// Get user by ID
|
||||
getUserById = async (id) => {
|
||||
try {
|
||||
const user = await getUserByIdDb(id);
|
||||
// user.password = undefined;
|
||||
user.is_active = user.is_active == 1 ? true : false
|
||||
if (!user) throw new ErrorHandler(404, "User not found");
|
||||
|
||||
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;
|
||||
} 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 {
|
||||
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) {
|
||||
throw new ErrorHandler(error.statusCode, error.message);
|
||||
throw new ErrorHandler(error.statusCode || 500, error.message);
|
||||
}
|
||||
};
|
||||
|
||||
updateUser = async (param) => {
|
||||
const { userName, id } = param;
|
||||
const errors = {};
|
||||
// Update user
|
||||
updateUser = async ({ user_id, fullname, name, email, phone, role_id, is_sa, is_active, is_approve }) => {
|
||||
try {
|
||||
const user = await getUserByIdDb(user_id);
|
||||
if (!user) throw new ErrorHandler(404, "User not found");
|
||||
|
||||
const user = await getUserByIdDb(id);
|
||||
|
||||
const findUserByUsername = await getUserByUsernameDb(userName, param.tenantID);
|
||||
|
||||
const usernameChanged = userName && user.user_name.toLowerCase() !== userName.toLowerCase();
|
||||
|
||||
if (usernameChanged && typeof findUserByUsername === "object") {
|
||||
errors["username"] = "Username is already taken";
|
||||
// Cek username
|
||||
if (name && user.user_name.toLowerCase() !== name.toLowerCase()) {
|
||||
const userByName = await getUserByUsernameDb(name);
|
||||
if (userByName) throw new ErrorHandler(400, "Username already taken");
|
||||
}
|
||||
|
||||
if (Object.keys(errors).length > 0) {
|
||||
throw new ErrorHandler(403, errors);
|
||||
}
|
||||
const updateData = {
|
||||
...(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) {
|
||||
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 {
|
||||
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) {
|
||||
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 {
|
||||
return await getAllRoleDb(tenantID);
|
||||
await deleteUserDb(userId, deletedBy);
|
||||
return { message: "User deleted successfully" };
|
||||
} 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