From eed438e27ce45674ae04e42cff2458c75f276757 Mon Sep 17 00:00:00 2001 From: fro1991 Date: Wed, 22 Oct 2025 14:03:50 +0700 Subject: [PATCH] update --- src/controllers/auth.ts | 678 ++++++++++++++++++++-------------------- 1 file changed, 339 insertions(+), 339 deletions(-) diff --git a/src/controllers/auth.ts b/src/controllers/auth.ts index cf37603..b395cfb 100644 --- a/src/controllers/auth.ts +++ b/src/controllers/auth.ts @@ -1,26 +1,26 @@ -import { Response, NextFunction } from "express"; -import { Request } from 'express-jwt' -import { ReturnHelper } from "../helpers/express/return"; -import { OrmHelper } from "../helpers/orm"; -import Joi from "joi"; -import config from "config"; -import { ILogObj, Logger } from "tslog"; -import { Language } from "../langs/lang"; -import { UAParser } from 'ua-parser-js'; -import dayjs from 'dayjs' -import jwt from 'jsonwebtoken'; -import fs from 'fs'; -import { v4 as uuidv4 } from 'uuid'; -import { Application, EmailBody, Menu, User, UserRefreshToken, UserRole } from "entity"; -import axios from 'axios'; -import CommonHelper from "../helpers/common"; -import { MoreThan } from "typeorm"; +import { Response, NextFunction } from "express" +import { Request } from "express-jwt" +import { ReturnHelper } from "../helpers/express/return" +import { OrmHelper } from "../helpers/orm" +import Joi from "joi" +import config from "config" +import { ILogObj, Logger } from "tslog" +import { Language } from "../langs/lang" +import { UAParser } from "ua-parser-js" +import dayjs from "dayjs" +import jwt from "jsonwebtoken" +import fs from "fs" +import { v4 as uuidv4 } from "uuid" +import { Application, EmailBody, Menu, User, UserRefreshToken, UserRole } from "entity" +import axios from "axios" +import CommonHelper from "../helpers/common" +import { MoreThan } from "typeorm" -const log: Logger = new Logger({ name: '[UserController]', type: 'pretty' }); +const log: Logger = new Logger({ name: "[UserController]", type: "pretty" }) export class AuthController { - static async login(req: Request, res: Response, next: NextFunction): Promise { - /* + static async login(req: Request, res: Response, next: NextFunction): Promise { + /* #swagger.tags = ['Auth'] #swagger.requestBody = { required: true, @@ -34,213 +34,215 @@ export class AuthController { } */ - try { - const schema = Joi.object().keys({ - username: Joi.string().max(64).required().label('Username'), - password: Joi.string().min(8).required().label('Password'), - application: Joi.string().required().label('Application'), - }); + try { + const schema = Joi.object().keys({ + username: Joi.string().max(64).required().label("Username"), + password: Joi.string().min(8).required().label("Password"), + application: Joi.string().required().label("Application"), + }) - const param: User & { application: string } = await schema.validateAsync(req.body); + const param: User & { application: string } = await schema.validateAsync(req.body) - const userRepository = OrmHelper.DB.getRepository(User); - const userRefreshTokenRepository = OrmHelper.DB.getRepository(UserRefreshToken); + const userRepository = OrmHelper.DB.getRepository(User) + const userRefreshTokenRepository = OrmHelper.DB.getRepository(UserRefreshToken) - const user = await userRepository.findOne({ - relations: ['roles', 'roles.application'], - select: ['id', 'email', 'name', 'nik', 'password', 'username', 'roles'], - where: { username: param.username }, - }) + const user = await userRepository.findOne({ + relations: ["roles", "roles.application"], + select: ["id", "email", "name", "nik", "password", "username", "roles"], + where: { username: param.username }, + }) - if (user != null && user.roles != null && user.roles.length > 0 && user.checkIfPasswordMatch(param.password)) { + if (user != null && user.roles != null && user.roles.length > 0 && user.checkIfPasswordMatch(param.password)) { + const { browser, device, os } = UAParser(req.get("User-Agent")) - const { browser, device, os } = UAParser(req.get('User-Agent')); + const refresh_token = new UserRefreshToken() + refresh_token.id_user = user.id + refresh_token.user_agent = req.get("User-Agent") + refresh_token.remote_addr = req.ip.split(":").pop() + refresh_token.browser = browser.name + " " + browser.version + refresh_token.os = os.name + " " + os.version + refresh_token.device = (device.model ?? "") + " " + (device.vendor ?? "") + refresh_token.platform = device.type ?? "desktop" + refresh_token.expired_at = dayjs().add(config.get("auth.refresh_token_lifetime_day"), "day").toDate() - const refresh_token = new UserRefreshToken(); - refresh_token.id_user = user.id; - refresh_token.user_agent = req.get('User-Agent'); - refresh_token.remote_addr = req.ip.split(':').pop(); - refresh_token.browser = browser.name + " " + browser.version; - refresh_token.os = os.name + " " + os.version; - refresh_token.device = (device.model ?? '') + " " + (device.vendor ?? ''); - refresh_token.platform = device.type ?? 'desktop'; - refresh_token.expired_at = dayjs().add(config.get('auth.refresh_token_lifetime_day'), 'day').toDate(); + await userRefreshTokenRepository.save(refresh_token) - await userRefreshTokenRepository.save(refresh_token); + // const userRoleRepository = OrmHelper.DB.getRepository(UserRole); - // const userRoleRepository = OrmHelper.DB.getRepository(UserRole); + let role_id = "" + let roles: UserRole - let role_id = ''; - let roles: UserRole; + if (user.roles) { + for (let r of user.roles) { + if (r.application.id == param.application) { + role_id = r.id + roles = r + } + } + } - if (user.roles) { - for (let r of user.roles) { - if (r.application.id == param.application) { - role_id = r.id; - roles = r; - } - } - } + if (role_id == "") { + return ReturnHelper.errorResponse(res, 403, 403, Language.lang.failed_access + ", you don't have any roles in this application") + } else { + // const userRole = await userRoleRepository.findOneBy({ id: role_id }) + var hrms = { + department_id: null, + department_name: null, + level_id: null, + level_name: null, + } - if (role_id == '') { - return ReturnHelper.errorResponse(res, 403, 403, Language.lang.failed_access + ', you don\'t have any roles in this application'); - } else { - // const userRole = await userRoleRepository.findOneBy({ id: role_id }) - var hrms = { - department_id: null, - department_name: null, - level_id: null, - level_name: null - } + if (user.nik) { + const url = config.get("service.hrms") + "api/get-employee?nik=" + user.nik + const { data: dataHrms } = await axios.get(url) + if (dataHrms && dataHrms.status && dataHrms.data.count == 1) { + hrms = { + department_id: dataHrms.data.list[0].idxdept, + department_name: dataHrms.data.list[0].departement, + level_id: dataHrms.data.list[0].idxlevel, + level_name: dataHrms.data.list[0].level, + } + } + } - if (user.nik) { - const url = config.get("service.hrms") + "api/get-employee?nik=" + user.nik; - const { data: dataHrms } = await axios.get(url); - if (dataHrms && dataHrms.status && dataHrms.data.count == 1) { - hrms = { - department_id: dataHrms.data.list[0].idxdept, - department_name: dataHrms.data.list[0].departement, - level_id: dataHrms.data.list[0].idxlevel, - level_name: dataHrms.data.list[0].level - } - } - } + var privateKey = fs.readFileSync("src/helpers/key/private.key") + var token = jwt.sign( + { + exp: Math.floor(Date.now() / 1000) + Number(config.get("auth.access_token_lifetime")), + data: { + id: user.id, + username: user.username, + name: user.name, + id_role: role_id, + roles: roles.roles, + nik: user.nik, + hrms: hrms, + }, + }, + privateKey, + { algorithm: "RS256" } + ) - var privateKey = fs.readFileSync('src/helpers/key/private.key'); + delete user.password - var token = jwt.sign( - { - exp: Math.floor(Date.now() / 1000) + (Number(config.get('auth.access_token_lifetime'))), - data: { - id: user.id, - username: user.username, - name: user.name, - id_role: role_id, - roles: roles.roles - } - }, - privateKey, - { algorithm: 'RS256' } - ); + const data = { + user: { ...user, ...hrms }, + role_name: roles.name, + roles_list: await AuthController.getListRole(roles.roles), + token: { + access_token: token, + refresh_token: refresh_token.refresh_token, + }, + } - delete user.password; + return ReturnHelper.successResponseAny(res, 200, Language.lang.success_login, data) + } + } - const data = { - user: { ...user, ...hrms }, - role_name: roles.name, - roles_list: await AuthController.getListRole(roles.roles), - token: { - access_token: token, - refresh_token: refresh_token.refresh_token - } - } + if (user.roles == null || user.roles.length == 0) { + return ReturnHelper.errorResponse(res, 403, 401, Language.lang.failed_access + ", you don\t have any roles in this application") + } else { + return ReturnHelper.errorResponse(res, 403, 402, Language.lang.failed_access) + } + } catch (e: unknown) { + log.error(e) + const err = e as Error - return ReturnHelper.successResponseAny(res, 200, Language.lang.success_login, data); - } - } + return ReturnHelper.errorResponse(res, 500, 403, Language.lang.failed_access, err.message) + } + } - if (user.roles == null || user.roles.length == 0) { - return ReturnHelper.errorResponse(res, 403, 401, Language.lang.failed_access + ', you don\t have any roles in this application'); - } else { - return ReturnHelper.errorResponse(res, 403, 402, Language.lang.failed_access); - } - } catch (e: unknown) { - log.error(e); - const err = e as Error; + static async getListRole(roles: any): Promise { + const repoMenu = OrmHelper.DB.getRepository(Menu) - return ReturnHelper.errorResponse(res, 500, 403, Language.lang.failed_access, err.message); - } - } + const whereAttr = [] + const whereVal = {} - static async getListRole(roles: any): Promise { - const repoMenu = OrmHelper.DB.getRepository(Menu); + for (let k in roles) { + let p = roles[k] - const whereAttr = []; - const whereVal = {}; + whereAttr.push("id = :id" + k) + whereVal["id" + k] = p + } - for (let k in roles) { - let p = roles[k]; + const res_list = repoMenu + .createQueryBuilder() + .where("(" + whereAttr.join(" or ") + ") and id_parent is null", whereVal) + .orderBy("order_number", "ASC") - whereAttr.push('id = :id' + k); - whereVal['id' + k] = p; - } + let list_data_final = await res_list.getMany() - const res_list = repoMenu.createQueryBuilder() - .where('(' + whereAttr.join(' or ') + ') and id_parent is null', whereVal) - .orderBy('order_number', 'ASC'); + if (list_data_final.length > 0) { + const res_list_all = await repoMenu + .createQueryBuilder() + .where("(" + whereAttr.join(" or ") + ") and id_parent is not null", whereVal) + .orderBy("order_number", "ASC") + .getMany() - let list_data_final = await res_list.getMany(); + let list_child: any = {} + for (let p of res_list_all) { + if (!list_child[p.id_parent]) { + list_child[p.id_parent] = [] + } - if (list_data_final.length > 0) { - const res_list_all = await repoMenu.createQueryBuilder() - .where('(' + whereAttr.join(' or ') + ') and id_parent is not null', whereVal) - .orderBy('order_number', 'ASC').getMany(); + delete p.status + delete p.created_at + delete p.updated_at + delete p.deleted_at - let list_child: any = {}; - for (let p of res_list_all) { - if (!list_child[p.id_parent]) { - list_child[p.id_parent] = []; - } + list_child[p.id_parent].push(p) + } - delete p.status - delete p.created_at - delete p.updated_at - delete p.deleted_at + for (let f of list_data_final) { + delete f.status + delete f.created_at + delete f.updated_at + delete f.deleted_at - list_child[p.id_parent].push(p); - } + if (list_child[f.id]) { + f.children = list_child[f.id] - for (let f of list_data_final) { - delete f.status - delete f.created_at - delete f.updated_at - delete f.deleted_at + for (let g of f.children) { + if (list_child[g.id]) { + g.children = list_child[g.id] - if (list_child[f.id]) { - f.children = list_child[f.id]; + for (let h of g.children) { + if (list_child[h.id]) { + h.children = list_child[h.id] - for (let g of f.children) { - if (list_child[g.id]) { - g.children = list_child[g.id]; + for (let i of h.children) { + if (list_child[i.id]) { + i.children = list_child[i.id] - for (let h of g.children) { - if (list_child[h.id]) { - h.children = list_child[h.id]; + for (let j of i.children) { + if (list_child[j.id]) { + j.children = list_child[j.id] - for (let i of h.children) { - if (list_child[i.id]) { - i.children = list_child[i.id]; + for (let k of j.children) { + if (list_child[k.id]) { + k.children = list_child[k.id] + } + } + } + } + } + } + } + } + } + } + } + } - for (let j of i.children) { - if (list_child[j.id]) { - j.children = list_child[j.id]; + return list_data_final + } - for (let k of j.children) { - if (list_child[k.id]) { - k.children = list_child[k.id]; - } - } - } - } - } - } - } - } - } - } - } - } + return {} + } - return list_data_final; - - } - - return {}; - } - - static async logout(req: Request, res: Response, next: NextFunction): Promise { - /* + static async logout(req: Request, res: Response, next: NextFunction): Promise { + /* #swagger.tags = ['Auth'] #swagger.parameters['refresh_token'] = { in: 'path', @@ -250,32 +252,32 @@ export class AuthController { } */ - try { - const schema = Joi.object().keys({ - refresh_token: Joi.string().uuid().required().label('Refresh Token'), - }); + try { + const schema = Joi.object().keys({ + refresh_token: Joi.string().uuid().required().label("Refresh Token"), + }) - const param: UserRefreshToken = await schema.validateAsync(req.params); + const param: UserRefreshToken = await schema.validateAsync(req.params) - const repo = OrmHelper.DB.getRepository(UserRefreshToken); + const repo = OrmHelper.DB.getRepository(UserRefreshToken) - const affected = (await repo.delete({ refresh_token: param.refresh_token })).affected; + const affected = (await repo.delete({ refresh_token: param.refresh_token })).affected - if (affected > 0) { - return ReturnHelper.successResponseAny(res, 200, Language.lang.success_logout); - } else { - return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_logout, ""); - } - } catch (e: unknown) { - log.error(e); - const err = e as Error; + if (affected > 0) { + return ReturnHelper.successResponseAny(res, 200, Language.lang.success_logout) + } else { + return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_logout, "") + } + } catch (e: unknown) { + log.error(e) + const err = e as Error - return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_logout, err.message); - } - } + return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_logout, err.message) + } + } - static async resetPassword(req: Request, res: Response, next: NextFunction): Promise { - /* + static async resetPassword(req: Request, res: Response, next: NextFunction): Promise { + /* #swagger.tags = ['Auth'] #swagger.parameters['email'] = { in: 'path', @@ -291,67 +293,65 @@ export class AuthController { } */ - try { - const schema = Joi.object().keys({ - email: Joi.string().email().required().label('Email'), - application: Joi.string().required().label('Application'), - }); + try { + const schema = Joi.object().keys({ + email: Joi.string().email().required().label("Email"), + application: Joi.string().required().label("Application"), + }) - const param: { email: string, application: string } = await schema.validateAsync(req.params); + const param: { email: string; application: string } = await schema.validateAsync(req.params) - const userRepository = OrmHelper.DB.getRepository(User); + const userRepository = OrmHelper.DB.getRepository(User) - const user = await userRepository.findOne({ - where: { email: param.email }, - }) + const user = await userRepository.findOne({ + where: { email: param.email }, + }) - user.reset_token = uuidv4(); + user.reset_token = uuidv4() - await userRepository.save(user); + await userRepository.save(user) - //send email reset password - const url = config.get("service.notification") + "api/email/send"; + //send email reset password + const url = config.get("service.notification") + "api/email/send" - // console.log(url, 'url') + // console.log(url, 'url') - const template_raw = fs.readFileSync('assets/reset_password.html').toString(); + const template_raw = fs.readFileSync("assets/reset_password.html").toString() - const appRepository = OrmHelper.DB.getRepository(Application); - const app = await appRepository.findOneBy({ id: param.application }) + const appRepository = OrmHelper.DB.getRepository(Application) + const app = await appRepository.findOneBy({ id: param.application }) + const pairMap = { + // 'LINK': config.get('auth.reset_password_url') + user.reset_token, + LINK: app.reset_password_url + user.reset_token, + NAME: user.name, + } - const pairMap = { - // 'LINK': config.get('auth.reset_password_url') + user.reset_token, - 'LINK': app.reset_password_url + user.reset_token, - 'NAME': user.name - } + const template = CommonHelper.generateTemplate(template_raw, pairMap) - const template = CommonHelper.generateTemplate(template_raw, pairMap); + const email: EmailBody = { + subject: "Reset Password", + to: [user.email], + cc: [], + bcc: [], + html: template, + } - const email: EmailBody = { - subject: "Reset Password", - to: [user.email], - cc: [], - bcc: [], - html: template - } + const { data } = await axios.post(url, email) - const { data } = await axios.post(url, email); + return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data) - return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data); + // return ReturnHelper.errorResponse(res, 403, 401, Language.lang.failed_access); + } catch (e: unknown) { + log.error(e) + const err = e as Error + return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed, err.message) + } + } - // return ReturnHelper.errorResponse(res, 403, 401, Language.lang.failed_access); - } catch (e: unknown) { - log.error(e); - const err = e as Error; - - return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed, err.message); - } - } - - static async renewToken(req: Request, res: Response, next: NextFunction): Promise { - /* + static async renewToken(req: Request, res: Response, next: NextFunction): Promise { + /* #swagger.tags = ['Auth'] #swagger.parameters['refresh_token'] = { in: 'path', @@ -366,80 +366,80 @@ export class AuthController { type: 'string' } */ - try { - const schema = Joi.object().keys({ - refresh_token: Joi.string().uuid().required().label('Refresh Token'), - application: Joi.string().required().label('Application'), - }); + try { + const schema = Joi.object().keys({ + refresh_token: Joi.string().uuid().required().label("Refresh Token"), + application: Joi.string().required().label("Application"), + }) - const param: UserRefreshToken & { application: string } = await schema.validateAsync(req.params); + const param: UserRefreshToken & { application: string } = await schema.validateAsync(req.params) - const userRefreshTokenRepo = OrmHelper.DB.getRepository(UserRefreshToken); + const userRefreshTokenRepo = OrmHelper.DB.getRepository(UserRefreshToken) - const refresh_token = await userRefreshTokenRepo.findOneBy({ refresh_token: param.refresh_token, expired_at: MoreThan(new Date()) }); + const refresh_token = await userRefreshTokenRepo.findOneBy({ refresh_token: param.refresh_token, expired_at: MoreThan(new Date()) }) - if (refresh_token != null) { - const userRepo = OrmHelper.DB.getRepository(User); + if (refresh_token != null) { + const userRepo = OrmHelper.DB.getRepository(User) - const user = await userRepo.findOne({ relations: ['roles', 'roles.application'], where: { id: refresh_token.id_user } }); + const user = await userRepo.findOne({ relations: ["roles", "roles.application"], where: { id: refresh_token.id_user } }) - let role_id = ''; - let roles: UserRole; + let role_id = "" + let roles: UserRole - if (user.roles != null && user.roles.length > 0) { - for (let r of user.roles) { - if (r.application.id == param.application) { - role_id = r.id; + if (user.roles != null && user.roles.length > 0) { + for (let r of user.roles) { + if (r.application.id == param.application) { + role_id = r.id - roles = r; - } - } - } else { - return ReturnHelper.errorResponse(res, 403, 401, Language.lang.failed_access + ', you don\'t have any roles in this application'); - } + roles = r + } + } + } else { + return ReturnHelper.errorResponse(res, 403, 401, Language.lang.failed_access + ", you don't have any roles in this application") + } - // const userRoleRepository = OrmHelper.DB.getRepository(UserRole); - // const userRole = await userRoleRepository.findOneBy({ id: role_id }); + // const userRoleRepository = OrmHelper.DB.getRepository(UserRole); + // const userRole = await userRoleRepository.findOneBy({ id: role_id }); - if (roles) { - var privateKey = fs.readFileSync('src/helpers/key/private.key'); + if (roles) { + var privateKey = fs.readFileSync("src/helpers/key/private.key") - var token = jwt.sign( - { - exp: Math.floor(Date.now() / 1000) + (Number(config.get('auth.access_token_lifetime'))), - data: { - id: user.id, - username: user.username, - name: user.name, - id_role: role_id, - roles: roles.roles - } - }, - privateKey, - { algorithm: 'RS256' } - ); + var token = jwt.sign( + { + exp: Math.floor(Date.now() / 1000) + Number(config.get("auth.access_token_lifetime")), + data: { + id: user.id, + username: user.username, + name: user.name, + id_role: role_id, + roles: roles.roles, + }, + }, + privateKey, + { algorithm: "RS256" } + ) - return ReturnHelper.successResponseAny(res, 200, Language.lang.success, { - token, - role_name: roles.name, - roles_list: await AuthController.getListRole(roles.roles) - }); - } else { - return ReturnHelper.errorResponse(res, 403, 402, Language.lang.failed_access + ', you don\'t have any roles in this application'); - } - } else { - return ReturnHelper.errorResponse(res, 404, 403, Language.lang.failed, ""); - } - } catch (e: unknown) { - log.error(e); - const err = e as Error; + return ReturnHelper.successResponseAny(res, 200, Language.lang.success, { + token, + role_name: roles.name, + roles_list: await AuthController.getListRole(roles.roles), + }) + } else { + return ReturnHelper.errorResponse(res, 403, 402, Language.lang.failed_access + ", you don't have any roles in this application") + } + } else { + return ReturnHelper.errorResponse(res, 404, 403, Language.lang.failed, "") + } + } catch (e: unknown) { + log.error(e) + const err = e as Error - return ReturnHelper.errorResponse(res, 500, 404, Language.lang.failed, err.message); - } - } + return ReturnHelper.errorResponse(res, 500, 404, Language.lang.failed, err.message) + } + } - static async updatePassword(req: Request, res: Response, next: NextFunction): Promise { - /* + static async updatePassword(req: Request, res: Response, next: NextFunction): Promise { + /* #swagger.tags = ['Auth'] #swagger.parameters['token'] = { @@ -462,37 +462,37 @@ export class AuthController { } */ - try { - const schema = Joi.object().keys({ - reset_token: Joi.string().uuid().required().label('Token'), - password: Joi.string().required().label('Password'), - retype_password: Joi.ref('password'), - }); + try { + const schema = Joi.object().keys({ + reset_token: Joi.string().uuid().required().label("Token"), + password: Joi.string().required().label("Password"), + retype_password: Joi.ref("password"), + }) - req.body.reset_token = req.params.token ?? ''; + req.body.reset_token = req.params.token ?? "" - const param: User = await schema.validateAsync(req.body); + const param: User = await schema.validateAsync(req.body) - const userRepository = OrmHelper.DB.getRepository(User); + const userRepository = OrmHelper.DB.getRepository(User) - const data = await userRepository.findOneBy({ reset_token: param.reset_token }); + const data = await userRepository.findOneBy({ reset_token: param.reset_token }) - if (data != null) { - data.password = param.password; - data.reset_token = null; - data.hashPassword(); + if (data != null) { + data.password = param.password + data.reset_token = null + data.hashPassword() - await userRepository.save(data); + await userRepository.save(data) - return ReturnHelper.successResponseAny(res, 200, Language.lang.success_update); - } else { - return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, ""); - } - } catch (e: unknown) { - log.error(e); - const err = e as Error; + return ReturnHelper.successResponseAny(res, 200, Language.lang.success_update) + } else { + return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, "") + } + } catch (e: unknown) { + log.error(e) + const err = e as Error - return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_update, err.message); - } - } -} \ No newline at end of file + return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_update, err.message) + } + } +}