From ee303081127fafff53d59727ceaabc3a34a22f47 Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Date: Fri, 10 Oct 2025 19:49:48 +0700 Subject: [PATCH] update crud user --- controllers/users.controller.js | 198 +++++++++++--------------------- db/user.db.js | 113 ++++++++++-------- routes/users.route.js | 29 ++--- 3 files changed, 141 insertions(+), 199 deletions(-) diff --git a/controllers/users.controller.js b/controllers/users.controller.js index 47c6d2d..328ea2f 100644 --- a/controllers/users.controller.js +++ b/controllers/users.controller.js @@ -1,169 +1,103 @@ -const userService = require("../services/user.service"); -const { ErrorHandler } = require("../helpers/error"); -const { setResponse } = require("../helpers/utils"); -const { userSchema, newPasswordSchema } = require("../validate/user.schema"); +const UserService = require('../services/user.service'); +const { setResponse, setResponsePaging, checkValidate } = require('../helpers/utils'); +const { userSchema, newPasswordSchema } = require('../validate/user.schema'); 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)); - } + static async getAll(req, res) { + const queryParams = req.query; + + const results = await UserService.getAllUsers(queryParams); + const response = await setResponsePaging(queryParams, results, 'Users retrieved successfully'); + + 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)); - } + static async getById(req, res) { + const { id } = req.params; + + const results = await UserService.getUserById(id); + const response = await setResponse(results, 'User retrieved successfully'); + + res.status(response.statusCode).json(response); } - // Create new user - static async createUser(req, res) { - try { - const { error, value } = userSchema.validate(req.body, { abortEarly: false }); + // Create user + static async create(req, res) { + const { error, value } = await checkValidate(userSchema, req); - if (error) { - const validationErrors = error.details.map((err) => err.message); - throw new ErrorHandler(400, validationErrors); - } - - // Kirim approved_by dari user yang bikin - const result = await userService.createUser({ - ...value, - approved_by: req.user.user_id - }); - - 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)); + if (error) { + return res.status(400).json(setResponse(error, 'Validation failed', 400)); } + + value.approved_by = req.user.user_id; + + const results = await UserService.createUser(value); + const response = await setResponse(results, 'User created successfully'); + + res.status(response.statusCode).json(response); } // 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 updatedById = req.user?.user_id; + static async update(req, res) { + const { id } = req.params; + const { error, value } = await checkValidate(userSchema, req); - const result = await userService.updateUser({ - user_id: parseInt(id, 10), - fullname, - name, - email, - phone, - role_id, - is_sa, - is_active, - is_approve, - updatedById - }); - - console.log("PARAM ID:", req.params); - console.log("BODY:", req.body); - - 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)); + if (error) { + return res.status(400).json(setResponse(error, 'Validation failed', 400)); } + + value.updated_by = req.user.user_id; + + const results = await UserService.updateUser(id, value); + const response = await setResponse(results, 'User updated successfully'); + + res.status(response.statusCode).json(response); } - // Delete user - static async deleteUser(req, res) { - try { - const { id } = req.params; - const deletedBy = req.user?.user_id; + // Soft delete user + static async delete(req, res) { + const { id } = req.params; - 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 results = await UserService.deleteUser(id, req.user.user_id); + const response = await setResponse(results, 'User deleted successfully'); + + res.status(response.statusCode).json(response); } // Change user password static async changePassword(req, res) { - try { - const { new_password } = req.body; const { id } = req.params; + const { error, value } = await checkValidate(newPasswordSchema, req); - if (!id || !new_password) { - throw new ErrorHandler(400, "user_id and new_password are required"); + if (error) { + return res.status(400).json(setResponse(error, 'Validation failed', 400)); } - const { error } = newPasswordSchema.validate({ new_password }); + const results = await UserService.changeUserPassword(id, value.new_password); + const response = await setResponse(results, 'Password changed successfully'); - if (error) { - const errors = error.details.reduce((acc, cur) => { - const field = Array.isArray(cur.path) ? cur.path.join('.') : String(cur.path); - if (!acc[field]) acc[field] = []; - acc[field].push(cur.message); - return acc; - }, {}); - return res.status(400).json(setResponse(errors, 'Validation failed', 400)); - } - - const result = await userService.changeUserPassword(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)); - } + res.status(response.statusCode).json(response); } // 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)); - } + static async getAllStatus(req, res) { + const results = await UserService.getAllStatusUsers(); + const response = await setResponse(results, 'Status list retrieved successfully'); + + res.status(response.statusCode).json(response); } // Approve user - static async approveUser(req, res) { - try { - const { id } = req.params; - const approverId = req.user?.user_id || null; + static async approve(req, res) { + 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)); - } + const results = await UserService.approveUser(id, approverId); + const response = await setResponse(results, 'User approved successfully'); + + res.status(response.statusCode).json(response); } } diff --git a/db/user.db.js b/db/user.db.js index 3776a26..bc77252 100644 --- a/db/user.db.js +++ b/db/user.db.js @@ -1,20 +1,45 @@ -const { query, buildFilterQuery, buildDynamicUpdate } = require("../config"); +const pool = 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" }, - ]); + let queryParams = []; - const whereClause = whereConditions.length - ? `AND ${whereConditions.join(" AND ")}` - : ""; + // Pagination + if (searchParams.limit) { + const page = Number(searchParams.page ?? 1) - 1; + queryParams = [Number(searchParams.limit ?? 10), page]; + } + + // Search + const { whereOrConditions, whereParamOr } = pool.buildStringOrIlike( + [ + "u.user_fullname", + "u.user_name", + "u.user_email", + "r.role_name" + ], + searchParams.criteria, + queryParams + ); + + queryParams = whereParamOr ? whereParamOr : queryParams; + + // Filter + const { whereConditions, whereParamAnd } = pool.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" }, + ], + queryParams + ); + + queryParams = whereParamAnd ? whereParamAnd : queryParams; const queryText = ` SELECT + COUNT(*) OVER() AS total_data, 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, @@ -24,11 +49,21 @@ const getAllUsersDb = async (searchParams = {}) => { 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 ${whereClause} + WHERE u.deleted_at IS NULL + ${whereConditions.length > 0 ? ` AND ${whereConditions.join(' AND ')}` : ''} + ${whereOrConditions ? whereOrConditions : ''} ORDER BY u.user_id ASC + ${searchParams.limit ? `OFFSET $2 ROWS FETCH NEXT $1 ROWS ONLY` : ''}; `; - const result = await query(queryText, queryParams); - return result.recordset; + + const result = await pool.query(queryText, queryParams); + + const total = + result?.recordset.length > 0 + ? parseInt(result.recordset[0].total_data, 10) + : 0; + + return { data: result.recordset, total }; }; // Get user by ID @@ -46,7 +81,7 @@ const getUserByIdDb = async (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 query(queryText, [id]); + const result = await pool.query(queryText, [id]); return result.recordset[0]; }; @@ -61,7 +96,7 @@ const getUserByUserEmailDb = async (email) => { 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 query(queryText, [email]); + const result = await pool.query(queryText, [email]); return result.recordset[0]; }; @@ -76,54 +111,35 @@ const getUserByUsernameDb = async (username) => { 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 query(queryText, [username]); + const result = await pool.query(queryText, [username]); return result.recordset[0]; }; // Create user const createUserDb = async (data) => { - 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; + const { query: queryText, values } = pool.buildDynamicInsert("m_users", data); + const result = await pool.query(queryText, values); + const insertedId = result.recordset[0]?.inserted_id; + return insertedId ? await getUserByIdDb(insertedId) : null; }; // Update user const updateUserDb = async (userId, data) => { - 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; + const { query: queryText, values } = pool.buildDynamicUpdate("m_users", data, { + user_id: userId, + }); + await pool.query(`${queryText} AND deleted_at IS NULL`, values); + return getUserByIdDb(userId); }; // 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 = CURRENT_TIMESTAMP WHERE user_id = $2 AND deleted_at IS NULL `; - await query(queryText, [newPassword, userId]); + await pool.query(queryText, [newPassword, userId]); return true; }; @@ -132,14 +148,13 @@ const deleteUserDb = async (userId, deletedBy) => { const queryText = ` UPDATE m_users SET - deleted_at = GETDATE(), + deleted_at = CURRENT_TIMESTAMP, deleted_by = $1, is_active = 0 WHERE user_id = $2 AND deleted_at IS NULL `; - - await query(queryText, [deletedBy, userId]); + await pool.query(queryText, [deletedBy, userId]); return true; }; diff --git a/routes/users.route.js b/routes/users.route.js index 5e6ab74..ff0a02b 100644 --- a/routes/users.route.js +++ b/routes/users.route.js @@ -5,26 +5,19 @@ const verifyAccess = require('../middleware/verifyAccess'); const router = express.Router(); -// Get all users -router.get('/', verifyToken.verifyAccessToken, UserController.getAllUsers); +router.route('/') + .get(verifyToken.verifyAccessToken, UserController.getAllUsers) + .post(verifyToken.verifyAccessToken, verifyAccess(), UserController.createUser); -// Get user by ID -router.get('/:id', verifyToken.verifyAccessToken, UserController.getUserById); +router.route('/:id') + .get(verifyToken.verifyAccessToken, UserController.getUserById) + .put(verifyToken.verifyAccessToken, verifyAccess(), UserController.updateUser) + .delete(verifyToken.verifyAccessToken, verifyAccess(), UserController.deleteUser); -// 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('/change-password/:id') + .put(verifyToken.verifyAccessToken, verifyAccess(), UserController.changePassword); +router.route('/:id/approve') + .put(verifyToken.verifyAccessToken, verifyAccess(), UserController.approveUser); module.exports = router;