diff --git a/controllers/roles.controller.js b/controllers/roles.controller.js new file mode 100644 index 0000000..d7ee09b --- /dev/null +++ b/controllers/roles.controller.js @@ -0,0 +1,71 @@ +const RolesService = require('../services/roles.service'); +const { setResponse, setResponsePaging, checkValidate } = require('../helpers/utils'); +const { updateRolesSchema, insertRolesSchema } = require('../validate/roles.schema'); + +class RolesController { + // Get all Roles + static async getAll(req, res) { + const queryParams = req.query; + + const results = await RolesService.getAllRoles(queryParams); + const response = await setResponsePaging(queryParams, results, 'Roles found') + + res.status(response.statusCode).json(response); + } + + // Get Roles by ID + static async getById(req, res) { + const { id } = req.params; + + const results = await RolesService.getRolesById(id); + const response = await setResponse(results, 'Roles found') + + res.status(response.statusCode).json(response); + } + + // Create Roles + static async create(req, res) { + const { error, value } = await checkValidate(insertRolesSchema, req) + + if (error) { + return res.status(400).json(setResponse(error, 'Validation failed', 400)); + } + + value.userId = req.user.user_id + + const results = await RolesService.createRoles(value); + const response = await setResponse(results, 'Roles created successfully') + + return res.status(response.statusCode).json(response); + } + + // Update Roles + static async update(req, res) { + const { id } = req.params; + + const { error, value } = checkValidate(updateRolesSchema, req) + + if (error) { + return res.status(400).json(setResponse(error, 'Validation failed', 400)); + } + + value.userId = req.user.user_id + + const results = await RolesService.updateRoles(id, value); + const response = await setResponse(results, 'Roles updated successfully') + + res.status(response.statusCode).json(response); + } + + // Soft delete Roles + static async delete(req, res) { + const { id } = req.params; + + const results = await RolesService.deleteRoles(id, req.user.user_id); + const response = await setResponse(results, 'Roles deleted successfully') + + res.status(response.statusCode).json(response); + } +} + +module.exports = RolesController; diff --git a/controllers/roles.controllers.js b/controllers/roles.controllers.js deleted file mode 100644 index cdd8864..0000000 --- a/controllers/roles.controllers.js +++ /dev/null @@ -1,160 +0,0 @@ -const roleDb = require("../db/role.db"); -const { setResponse } = require("../helpers/utils"); - -module.exports = { - getAllRoles: async (req, res) => { - try { - const { search } = req.query; - const roles = await roleDb.getAllRolesDb(search || ''); - - return res.status(200).json(setResponse(roles, 'Roles retrieved successfully', 200)); - } catch (err) { - return res.status(err.statusCode || 500).json( - setResponse([], err.message || 'Failed to retrieve roles', err.statusCode || 500) - ); - } - }, - - getRolesById: async (req, res, next) => { - try { - const { id } = req.params; - - if (!id) { - return res.status(400).json(setResponse(null, "Role ID is required", 400)); - } - - const role = await roleDb.getRoleByIdDb(id); - - if (!role) { - return res.status(404).json(setResponse(null, "Role not found", 404)); - } - - return res.status(200).json(setResponse(role, "Role retrieved successfully", 200)); - } catch (err) { - next(err); - } - }, - - createRoles: async (req, res, next) => { - try { - let { role_name, role_description, role_level, updated_by} = req.body; - - if (!role_name || role_level === undefined || role_level === null) { - return res.status(400).json( - setResponse( - null, - "Please provide role_name and role_level", - 400 - ) - ); - } - - const level = parseInt(role_level); - if (isNaN(level)) { - return res.status(400).json( - setResponse( - null, - "role_level must be a number", - 400 - ) - ); - } - - const dataToCreate = { - role_name, - role_description, - updated_by, - role_level: level, - }; - - Object.keys(dataToCreate).forEach( - (key) => dataToCreate[key] === undefined && delete dataToCreate[key] - ); - - const insertedId = await roleDb.createRoleDb(dataToCreate); - - const newRole = insertedId - ? await roleDb.getRoleByIdDb(insertedId) - : { role_id: null, ...dataToCreate }; - - return res.status(201).json(setResponse(newRole, "Role has been created!", 201)); - } catch (err) { - next(err); - } - }, - - updateRoles: async (req, res, next) => { - try { - const { id } = req.params; - const { role_name, role_description, role_level, updated_by } = req.body; - - if (!id) { - return res.status(400).json(setResponse(null, "Role ID is required", 400)); - } - - const dataToUpdate = {}; - - if (role_name) dataToUpdate.role_name = role_name; - - if (Object.prototype.hasOwnProperty.call(req.body, "role_description")) { - dataToUpdate.role_description = role_description; - } - - if (role_level !== undefined && role_level !== null) { - const level = parseInt(role_level); - if (isNaN(level)) { - return res.status(400).json(setResponse(null, "role_level must be a number", 400)); - } - dataToUpdate.role_level = level; - } - - if (updated_by) dataToUpdate.updated_by = updated_by; - - if (Object.keys(dataToUpdate).length === 0) { - return res.status(400).json(setResponse(null, "No valid data provided for update", 400)); - } - - const existingRole = await roleDb.getRoleByIdDb(id); - if (!existingRole || existingRole.length === 0) { - return res.status(404).json(setResponse(null, "Role not found", 404)); - } - - await roleDb.updateRoleDb(id, dataToUpdate); - - const updatedRole = await roleDb.getRoleByIdDb(id); - - return res.status(200).json(setResponse(updatedRole, "Role has been updated successfully", 200)); - } catch (err) { - next(err); - } - }, - - - deleteRoles: async (req, res, next) => { - try { - const { id } = req.params; - const deletedBy = req.user?.id || 1; - - if (!id) { - return res.status(400).json(setResponse(null, "Role ID is required", 400)); - } - - const existingRole = await roleDb.getRoleByIdDb(id); - if (!existingRole) { - return res.status(404).json(setResponse(null, "Role not found", 404)); - } - - await roleDb.deleteRoleDb(id, deletedBy); - - return res.status(200).json( - setResponse( - null, - "Role has been soft deleted successfully", - 200 - ) - ); - } catch (err) { - next(err); - } - }, -}; \ No newline at end of file diff --git a/db/role.db.js b/db/role.db.js deleted file mode 100644 index e49b110..0000000 --- a/db/role.db.js +++ /dev/null @@ -1,95 +0,0 @@ -const pool = require("../config"); - -// Get all roles -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 - 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, queryParams); - return result.recordset; -}; - -// Get role by ID -const getRoleByIdDb = async (id) => { - const queryText = ` - 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, [id]); - return result.recordset; -}; - -// Create role -const createRoleDb = async (data) => { - const roles = { ...data }; - - const { query, values } = pool.buildDynamicInsert("m_roles", { - ...roles, - }); - - const result = await pool.query(query, values); - return result.recordset[0]?.inserted_id || null; -}; - - - -// Update role -const updateRoleDb = async (id, data) => { - const { query, values } = pool.buildDynamicUpdate( - "m_roles", - { ...data }, - { role_id: id } - ); - await pool.query(query, values); - return true; -}; - -// Soft delete role -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, id]); - return true; -}; - -module.exports = { - getAllRolesDb, - getRoleByIdDb, - createRoleDb, - updateRoleDb, - deleteRoleDb, -}; diff --git a/db/roles.db.js b/db/roles.db.js new file mode 100644 index 0000000..82215e8 --- /dev/null +++ b/db/roles.db.js @@ -0,0 +1,114 @@ +const pool = require("../config"); + +// Get all roles +const getAllRolesDb = async (searchParams = {}) => { + let queryParams = []; + + // Pagination + if (searchParams.limit) { + const page = Number(searchParams.page ?? 1) - 1; + queryParams = [Number(searchParams.limit ?? 10), page]; + } + + // Filtering + const { whereConditions, whereParamAnd } = pool.buildFilterQuery( + [ + { column: "r.role_name", param: searchParams.role_name, type: "string" }, + { column: "r.role_level", param: searchParams.role_level, type: "number" }, + ], + queryParams + ); + + queryParams = whereParamAnd ? whereParamAnd : queryParams; + + const queryText = ` + SELECT + COUNT(*) OVER() AS total_data, + 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, + r.created_by + FROM m_roles r + WHERE r.deleted_at IS NULL + ${whereConditions.length > 0 ? `AND ${whereConditions.join(" AND ")}` : ""} + ORDER BY r.role_id ASC + ${searchParams.limit ? `OFFSET $2 ROWS FETCH NEXT $1 ROWS ONLY` : ''}; + `; + + 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 role by ID +const getRolesByIdDb = async (id) => { + const queryText = ` + 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, + r.created_by + FROM m_roles r + WHERE r.role_id = $1 AND r.deleted_at IS NULL + `; + const result = await pool.query(queryText, [id]); + return result.recordset; +}; + +// Create role +const createRolesDB = async (data) => { + const store = { ...data }; + + const { query: queryText, values } = pool.buildDynamicInsert("m_roles", store); + const result = await pool.query(queryText, values); + + const insertedId = result.recordset[0]?.inserted_id; + return insertedId ? await getRolesByIdDb(insertedId) : null; +}; + +// Update role +const updateRolesDb = async (id, data) => { + const store = { ...data }; + const whereData = { role_id: id }; + + const { query: queryText, values } = pool.buildDynamicUpdate("m_roles", store, whereData); + await pool.query(`${queryText} AND deleted_at IS NULL`, values); + + return getRolesByIdDb(id); +}; + +// Soft delete role +const deleteRolesDb = async (id, deletedBy) => { + const queryText = ` + UPDATE m_roles + SET deleted_at = CURRENT_TIMESTAMP, + deleted_by = $1 + WHERE role_id = $2 AND deleted_at IS NULL + `; + await pool.query(queryText, [deletedBy, id]); + return true; +}; + +module.exports = { + getAllRolesDb, + getRolesByIdDb, + createRolesDB, + updateRolesDb, + deleteRolesDb, +}; diff --git a/routes/roles.route.js b/routes/roles.route.js index 743760a..44094ed 100644 --- a/routes/roles.route.js +++ b/routes/roles.route.js @@ -1,13 +1,17 @@ const express = require('express'); +const Rolesontroller = require('../controllers/roles.controller'); +const verifyToken = require("../middleware/verifyToken") +const verifyAccess = require("../middleware/verifyAccess") + const router = express.Router(); -const { createRoles, getAllRoles, deleteRoles, updateRoles, getRolesById } = require("../controllers/roles.controllers"); - -router.post("/roles", createRoles); -router.get("/roles", getAllRoles); -router.get("/roles/:id", getRolesById) -router.delete("/roles/:id", deleteRoles); -router.put("/roles/:id", updateRoles); +router.route("/") + .get(verifyToken.verifyAccessToken, Rolesontroller.getAll) + .post(verifyToken.verifyAccessToken, verifyAccess(), Rolesontroller.create); +router.route("/:id") + .get(verifyToken.verifyAccessToken, Rolesontroller.getById) + .put(verifyToken.verifyAccessToken, verifyAccess(), Rolesontroller.update) + .delete(verifyToken.verifyAccessToken, verifyAccess(), Rolesontroller.delete); module.exports = router; \ No newline at end of file diff --git a/services/roles.service.js b/services/roles.service.js new file mode 100644 index 0000000..db73834 --- /dev/null +++ b/services/roles.service.js @@ -0,0 +1,88 @@ +const { + getAllRolesDb, + getRolesByIdDb, + createRolesDB, + updateRolesDb, + deleteRolesDb +} = require('../db/roles.db'); +const { ErrorHandler } = require('../helpers/error'); + +class RolesService { + // Get all Roles + static async getAllRoles(param) { + try { + const results = await getAllRolesDb(param); + + results.data.map(element => { + }); + + return results + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } + + // Get Roles by ID + static async getRolesById(id) { + try { + const result = await getRolesByIdDb(id); + + if (result.length < 1) throw new ErrorHandler(404, 'Roles not found'); + + return result; + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } + + // Create Roles + static async createRoles(data) { + try { + if (!data || typeof data !== 'object') data = {}; + + const result = await createRolesDB(data); + + return result; + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } + + // Update Roles + static async updateRoles(id, data) { + try { + if (!data || typeof data !== 'object') data = {}; + + const dataExist = await getRolesByIdDb(id); + + if (dataExist.length < 1) { + throw new ErrorHandler(404, 'Roles not found'); + } + + const result = await updateRolesDb(id, data); + + return result; + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } + + // Soft delete Roles + static async deleteRoles(id, userId) { + try { + const dataExist = await getRolesByIdDb(id); + + if (dataExist.length < 1) { + throw new ErrorHandler(404, 'Roles not found'); + } + + const result = await deleteRolesDb(id, userId); + + return result; + } catch (error) { + throw new ErrorHandler(error.statusCode, error.message); + } + } +} + +module.exports = RolesService; diff --git a/validate/roles.schema.js b/validate/roles.schema.js new file mode 100644 index 0000000..f8bb585 --- /dev/null +++ b/validate/roles.schema.js @@ -0,0 +1,23 @@ +// ======================== +// Device Validation + +const Joi = require("joi"); + +// ======================== +const insertRolesSchema = Joi.object({ + role_name: Joi.string().max(100).required(), + role_level: Joi.number().required(), + role_description: Joi.string().max(100).required(), +}); + +const updateRolesSchema = Joi.object({ + role_name: Joi.string().max(100), + role_level: Joi.number(), + role_description: Joi.string().max(100), +}).min(1); + + +// ✅ Export dengan CommonJS +module.exports = { + insertRolesSchema, updateRolesSchema +}; \ No newline at end of file