From db4bf2bf847d3e2b5d9f9da965826373a93c72bd Mon Sep 17 00:00:00 2001 From: adriano Date: Mon, 18 Mar 2024 15:18:18 -0300 Subject: [PATCH] feat: Add routes and controllers to integrate with E-Trust Horacius for user and application management --- .gitignore | 3 +- ESPACO-LAZER-IAM.MD | 82 -- backend/src/controllers/IAMControllerEL.ts | 737 ++++++++++-------- ...20240315203708-add-secondaryId-to-users.ts | 14 + backend/src/middleware/verifyAPIKey.ts | 2 +- backend/src/models/User.ts | 11 +- backend/src/routes/iamRoutesEL.ts | 53 +- .../UserServices/CheckUserRightService.ts | 33 - .../UserServices/CreateUserService.ts | 43 +- .../UserServices/DeleteUserService.ts | 14 +- .../services/UserServices/LinkUserRight.ts | 33 - .../services/UserServices/ResetPassword.ts | 32 - .../services/UserServices/UnlinkUserRight.ts | 33 - .../UserServices/UpdateUserService.ts | 71 +- 14 files changed, 582 insertions(+), 579 deletions(-) delete mode 100644 ESPACO-LAZER-IAM.MD create mode 100644 backend/src/database/migrations/20240315203708-add-secondaryId-to-users.ts delete mode 100644 backend/src/services/UserServices/CheckUserRightService.ts delete mode 100644 backend/src/services/UserServices/LinkUserRight.ts delete mode 100644 backend/src/services/UserServices/ResetPassword.ts delete mode 100644 backend/src/services/UserServices/UnlinkUserRight.ts diff --git a/.gitignore b/.gitignore index c86c332..4dd37d9 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,5 @@ WWebJS npm-debug.log* yarn-debug.log* -yarn-error.log* \ No newline at end of file +yarn-error.log* + diff --git a/ESPACO-LAZER-IAM.MD b/ESPACO-LAZER-IAM.MD deleted file mode 100644 index 7c058d9..0000000 --- a/ESPACO-LAZER-IAM.MD +++ /dev/null @@ -1,82 +0,0 @@ -# O que fazer? - -- Quando um usuário for criado na plataforma do E-trust Horacius, a aplicação do Omnihit deve criar o mesmo usuário no Banco de Dados do Omnihit. - - Criação - - Atualização - - Exclusão -- Quando um usuário for criado com um **profile(role)**, a aplicação do Omnihit deve alterar o profile - - Tipos de roles: `admin`, `user`, `supervisor` - - Atualização - - Exclusão - -# Como fazer? - -- Elaborar forma de autenticação -- Criar uma aplicação REST seguindo o protocolo especificado na documentação do Horacius - - Níveis - - 1: Da para fazer - - 2: Tem que analisar - - Users - - [ ] CheckUser (1) - - [ ] CreateUser (1) - - [ ] DeleteUser (1) - - [ ] UpdateUser (1) - - [ ] ResetPassword (1) - - [ ] LockUser (2) - - [ ] UnlockUser (2) - - [ ] ListAllUsers **OPCIONAL** - - Rights - - [ ] CheckUserRight (1) - - [ ] CreateRight (1) - - [ ] UpdateRight (1) - - [ ] DeleteRight (1) - - [ ] GetAllRights **OPCIONAL** - - Users X Rights - - [ ] LinkUserAndUserRight (1) - - [ ] UnlinkUserAndUserRight (1) - - [ ] GetAllUserRights **OPCIONAL** - -# Atribuições - -- Henrriky - - [ ] Verify token middleware - - [X] CheckUser (1) - - [ ] Routes - - [X] Controller - - [X] Service - - [X] Error handling - - [X] CreateUser (1) - - [ ] Routes - - [X] Controller - - [X] Service - - [X] Error handling - - [X] DeleteUser (1) - - [ ] Routes - - [X] Controller - - [X] Service - - [X] Error handling - - [X] UpdateUser (1) - - [ ] Routes - - [X] Controller - - [X] Service - - [X] Error handling - - [X] ResetPassword (1) - - [ ] Routes - - [X] Controller - - [X] Service - - [X] Error handling - - [X] LinkUserAndUserRight (1) - - [ ] Routes - - [X] Controller - - [X] Service - - [X] Error handling - - [X] UnlinkUserAndUserRight (1) - - [ ] Routes - - [X] Controller - - [X] Service - - [X] Error handling - - [X] CheckUserRight (1) - - [ ] Routes - - [X] Controller - - [X] Service - - [X] Error handling \ No newline at end of file diff --git a/backend/src/controllers/IAMControllerEL.ts b/backend/src/controllers/IAMControllerEL.ts index e759acd..c3cd8b7 100644 --- a/backend/src/controllers/IAMControllerEL.ts +++ b/backend/src/controllers/IAMControllerEL.ts @@ -1,15 +1,9 @@ import { Request, Response } from "express"; import { getIO } from "../libs/socket"; - -import AppError from "../errors/AppError"; - +import { Op } from "sequelize"; import CreateUserService from "../services/UserServices/CreateUserService"; -import ListUsersService from "../services/UserServices/ListUsersService"; import UpdateUserService from "../services/UserServices/UpdateUserService"; -import ShowUserService from "../services/UserServices/ShowUserService"; import DeleteUserService from "../services/UserServices/DeleteUserService"; - -import ListUser from "../services/UserServices/ListUserParamiterService"; import { del, get, set } from "../helpers/RedisClient"; import { @@ -17,39 +11,56 @@ import { stopWhoIsOnlineMonitor } from "../helpers/WhoIsOnlineMonitor"; -import { format, subMonths } from "date-fns"; -import { ptBR } from "date-fns/locale"; -import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue"; -import { splitDateTime } from "../helpers/SplitDateTime"; -import ListUserByWhatsappQueuesService from "../services/UserServices/ListUserByWhatsappQueuesService"; -import { getSettingValue } from "../helpers/WhaticketSettings"; -import { setBotInfo } from "../helpers/SetBotInfo"; -import { logger } from "../utils/logger"; -import ResetPasswordService from "../services/UserServices/ResetPassword"; -import CheckUserRightService from "../services/UserServices/CheckUserRightService"; -import UnlinkUserRightService from "../services/UserServices/UnlinkUserRight"; -import LinkUserRightService from "../services/UserServices/LinkUserRight"; +import User from "../models/User"; -interface IAMResponse { - return_code: string - return_msg: string -} +export const createUser = async ( + req: Request, + res: Response +): Promise => { + const { user_id, user_first_name, user_tax_id, user_email, user_title }: any = + req.body; -//TODO: REVIEW CREATE USER -export const createUser = async (req: Request, res: Response): Promise => { - try { - const { user_id, user_first_name, user_tax_id } = req.body; - //user_id ou cria uma tabela nova ou um atributo novo - const user = await CreateUserService({ - email: user_tax_id, - password: "padrao", - name: user_first_name, - }); + const invalid = invalidProperties(req.body, [ + "user_id", + "user_tax_id", + "user_first_name" + ]); - if (user) { - const { id, name } = user; - await set(`user:${id}`, { id, name }); - } + if (invalid) { + return res.status(400).json(response("1", `${invalid}`, "0", "createUser")); + } + + const auxUser = await User.findOne({ where: { secondaryId: user_id } }); + + if (auxUser) { + return res + .status(400) + .json( + response("1", `The user ${user_id} already exist`, "0", "createUser") + ); + } + + const user = await CreateUserService({ + email: user_tax_id || user_email, + password: "12345", + name: user_first_name, + positionCompany: user_title, + profile: "user", + ignoreThrow: true + }); + + if (user?.error) { + return res + .status(user?.status) + .json(response("0", `${user?.msg}`, "0", "createUser")); + } + + if (!user?.error) { + const _user = await User.findByPk(user.id); + _user?.update({ secondaryId: user_id }); + + const { id, name } = user; + await set(`user:${id}`, { id, name }); const io = getIO(); io.emit("user", { @@ -58,310 +69,426 @@ export const createUser = async (req: Request, res: Response): Promise => { - try { - const { user_id } = req.body; - await ShowUserService(user_id); - return res.status(200).json({ - return_code: "200", - return_msg: "", - user_exists: "1" - }); - } catch (error) { +export const deleteUser = async ( + req: Request, + res: Response +): Promise => { + const { user_id }: any = req.body; - if (error instanceof AppError) { - logger.warn(error); - return res.status(error.statusCode).json({ - return_code: String(error.statusCode), - return_msg: error.message, - user_exists: "0", - }); + const invalid = invalidProperties(req.body, ["user_id"]); + + if (invalid) { + return res.status(400).json(response("1", `${invalid}`, "0", "deleteUser")); + } + + const _user = await User.findOne({ where: { secondaryId: user_id } }); + + if (_user) { + const user = await DeleteUserService(_user.id, true); + + if (user?.error) { + return res + .status(user?.status) + .json(response("0", `${user?.msg}`, "0", "deleteUser")); } - return res.status(500).json({ - return_code: "500", - return_msg: "Internal server error", - user_exists: "0", - }); + if (!user?.error) { + del(`user:${_user.id}`); + + const io = getIO(); + io.emit("user", { + action: "delete", + userId: _user.id + }); + + await stopWhoIsOnlineMonitor(); + + io.emit("onlineStatus", { + action: "delete", + userOnlineTime: _user.id + }); + + await startWhoIsOnlineMonitor(); + + return res + .status(200) + .json(response("1", `User ${user_id} deleted`, "1", "deleteUser")); + } } + + return res + .status(500) + .json(response("0", "Internal server error", "0", "deleteUser")); }; -//TODO: REVIEW DELETE USER -export const deleteUser = async (req: Request, res: Response): Promise => { - try { - const { user_id } = req.body; +export const listAllUsers = async ( + req: Request, + res: Response +): Promise => { + const _users: any = await User.findAll({ + where: { + secondaryId: { + [Op.ne]: "" + } + }, + attributes: ["secondaryId", "name"] + }); - await DeleteUserService(user_id); - - del(`user:${user_id}`); - - const io = getIO(); - io.emit("user", { - action: "delete", - user_id + if (_users) { + const user_list = _users.map((user: any) => { + const { secondaryId, name } = user; + return { user_id: secondaryId, full_name: name }; }); - //test del - await stopWhoIsOnlineMonitor(); - - io.emit("onlineStatus", { - action: "delete", - userOnlineTime: user_id - }); - - await startWhoIsOnlineMonitor(); - return res.status(200).json({ - return_code: "200", - return_msg: `User ${user_id} deleted`, - user_removed: "1", - }); - - } catch (error) { - if (error instanceof AppError) { - logger.warn(error); - return res.status(error.statusCode).json({ - return_code: String(error.statusCode), - return_msg: error.message, - user_removed: "0", - }); - } - - return res.status(500).json({ - return_code: "500", - return_msg: "Internal server error", - user_removed: "0", - }); + return res + .status(200) + .json(response("1", "Success", user_list, "listAllUsers")); } + + return res + .status(500) + .json(response("0", "Internal server error", [], "listAllUsers")); }; -//TODO: REVIEW UPDATE USER -export const updateUser = async (req: Request, res: Response): Promise => { - try { - const { user_id, user_first_name, user_tax_id } = req.body; - // const dateToday = splitDateTime(new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))); - // const currentDate = new Date(); - // const tenMonthsAgo = subMonths(currentDate, 10); - // const formattedDate = format(tenMonthsAgo, "yyyy-MM-dd"); - // console.log("dateToday.fullDate: ", dateToday.fullDate); - // console.log("formattedDate 10 months ago: ", formattedDate); +export const checkUser = async ( + req: Request, + res: Response +): Promise => { + const { user_id }: any = req.body; - // const openByUserOnQueue: any[] = await CountTicketsByUserQueue({ - // startDate: formattedDate, - // endDate: dateToday.fullDate, - // status: "open", - // clientChatStart: true, - // userId: userId - // }); - // let userQueuesAttendance = []; + const invalid = invalidProperties(req.body, ["user_id"]); - // if ((openByUserOnQueue && openByUserOnQueue.length) > 0) { - // userQueuesAttendance = openByUserOnQueue.filter( - // (e: any) => !userData.queueIds.includes(e.queueId) - // ); - - // if (userQueuesAttendance && userQueuesAttendance.length > 0) { - // const queueInAttendance = userQueuesAttendance.map(e => e.queueId); - // const mergedSet = new Set([...userData.queueIds, ...queueInAttendance]); - - // userData.queueIds = Array.from(mergedSet); - // } - // } - const userData = { - email: user_tax_id, - name: user_first_name, - } - // email?: string; - // name?: string; - // password?: string; - // positionCompany?: string; - // profile?: string; - // queueIds?: number[]; - let user: any = await UpdateUserService({ userData, userId: user_id }); - await setBotInfo(user); - - if (user) { - const { id, name } = user; - await set(`user:${id}`, { id, name }); - } - - const io = getIO(); - io.emit("user", { - action: "update", - user - }); - - // user.userQueuesAttendance = userQueuesAttendance; - return res.status(200).json({ - return_code: "200", - return_msg: `User ${user_id} updated`, - user_updated: "1" - }); - } catch (error) { - if (error instanceof AppError) { - logger.warn(error); - return res.status(error.statusCode).json({ - return_code: String(error.statusCode), - return_msg: error.message, - user_updated: "0", - }); - } - - return res.status(500).json({ - return_code: "500", - return_msg: "Internal server error", - user_updated: "0", - }); + if (invalid) { + return res.status(400).json(response("1", `${invalid}`, "0", "checkUser")); } + + const _user = await User.findOne({ where: { secondaryId: user_id } }); + + if (_user) { + return res + .status(200) + .json(response("1", `User ${user_id} exist`, "1", "checkUser")); + } + + return res + .status(404) + .json(response("1", `User ${user_id} not exist`, "0", "checkUser")); }; -export const resetPassword = async (req: Request, res: Response): Promise => { - try { - const { user_id, user_password } = req.body; +export const updateUser = async ( + req: Request, + res: Response +): Promise => { + const { user_id, user_first_name, user_tax_id, user_email, user_title }: any = + req.body; - await ResetPasswordService({ - userPassword: user_password, - userId: user_id - }) + const invalid = invalidProperties(req.body, ["user_id"]); - return res.status(200).json({ - return_code: "200", - return_msg: `User has the password changed`, - password_set: "1" - }); - } catch (error) { - if (error instanceof AppError) { - logger.warn(error); - return res.status(error.statusCode).json({ - return_code: String(error.statusCode), - return_msg: error.message, - password_set: "0", - }); - } - - return res.status(500).json({ - return_code: "500", - return_msg: "Internal server error", - password_set: "0", - }); + if (invalid) { + return res.status(400).json(response("1", `${invalid}`, "0", "checkUser")); } + const _user: any = await User.findOne({ where: { secondaryId: user_id } }); + + if (!_user) + return res + .status(404) + .json(response("1", `User ${user_id} not exist`, "0", "updateUser")); + + const userData = { + email: user_tax_id || user_email, + name: user_first_name, + positionCompany: user_title + }; + + let user: any = await UpdateUserService({ + userData, + userId: _user.id, + ignoreThrow: true + }); + + if (user?.error) { + return res + .status(user?.status) + .json(response("0", `${user?.msg}`, "0", "updateUser")); + } + + if (user) { + const { id, name } = user; + await set(`user:${id}`, { id, name }); + } + + const io = getIO(); + io.emit("user", { + action: "update", + user + }); + + return res + .status(200) + .json(response("1", `User ${user_id} updated`, "1", "updateUser")); }; -export const linkUserRight = async (req: Request, res: Response): Promise => { - try { - const { user_id, user_right_title, } = req.body; +export const resetPassword = async ( + req: Request, + res: Response +): Promise => { + const { user_id, user_password }: any = req.body; - await LinkUserRightService({ - userProfile: user_right_title, - userId: user_id - }) + const invalid = invalidProperties(req.body, ["user_id", "user_password"]); - return res.status(200).json({ - return_code: "200", - return_msg: `User ${user_id} associated`, - user_right_linked: "1" - }); - } catch (error) { - if (error instanceof AppError) { - logger.warn(error); - return res.status(error.statusCode).json({ - return_code: String(error.statusCode), - return_msg: error.message, - user_right_linked: "0", - }); - } - - return res.status(500).json({ - return_code: "500", - return_msg: "Internal server error", - user_right_linked: "0", - }); + if (invalid) { + return res + .status(400) + .json(response("1", `${invalid}`, "0", "resetPassword")); } + + const _user = await User.findOne({ where: { secondaryId: user_id } }); + + if (!_user) { + return res + .status(404) + .json(response("1", `User ${user_id} not exist`, "0", "resetPassword")); + } + + const userData = { + password: user_password, + email: _user.email + }; + + let user: any = await UpdateUserService({ + userData, + userId: _user.id, + ignoreThrow: true + }); + + if (user?.error) { + return res + .status(user?.status) + .json(response("0", `${user?.msg}`, "0", "resetPassword")); + } + + await logoutUser(_user.id); + + return res + .status(200) + .json( + response("1", `User ${user_id} password updated`, "1", "resetPassword") + ); }; -export const unlinkUserRight = async (req: Request, res: Response): Promise => { - try { - const { user_id, user_right_title } = req.body; +export const linkUserAndUserRight = async ( + req: Request, + res: Response +): Promise => { + const { user_id, user_right_id, user_right_title }: any = req.body; - await UnlinkUserRightService({ - userProfile: user_right_title, - userId: user_id - }) + const invalid = invalidProperties(req.body, ["user_id", "user_right_id"]); - return res.status(200).json({ - return_code: "200", - return_msg: `User ${user_id} deassociated`, - user_right_unlinked: "1", - }); - } catch (error) { - if (error instanceof AppError) { - logger.warn(error); - return res.status(error.statusCode).json({ - return_code: String(error.statusCode), - return_msg: error.message, - user_right_unlinked: "0", - }); - } - - return res.status(500).json({ - return_code: "500", - return_msg: "Internal server error", - user_right_unlinked: "0", - }); + if (invalid) { + return res + .status(400) + .json(response("1", `${invalid}`, "0", "linkUserAndUserRight")); } + + if ( + (user_right_id && + !["admin", "user", "supervisor"].includes( + user_right_id?.trim().toLocaleLowerCase() + )) || + (user_right_title && + !["admin", "user", "supervisor"].includes( + user_right_title?.trim().toLocaleLowerCase() + )) + ) { + return res + .status(400) + .json( + response( + "1", + `The user profile ${ + user_right_title || user_right_id + } provided by the property user_right_title or user_right_id does not match the following profiles: admin, user, supervisor`, + "0", + "linkUserAndUserRight" + ) + ); + } + + const _user: any = await User.findOne({ where: { secondaryId: user_id } }); + + if (!_user) + return res + .status(404) + .json( + response("1", `User ${user_id} not exist`, "0", "linkUserAndUserRight") + ); + + const userData = { + profile: user_right_title || user_right_id, + email: _user.email + }; + + let user: any = await UpdateUserService({ + userData, + userId: _user.id, + ignoreThrow: true + }); + + if (user?.error) { + return res + .status(user?.status) + .json(response("0", `${user?.msg}`, "0", "linkUserAndUserRight")); + } + + await logoutUser(_user.id); + + return res + .status(200) + .json( + response( + "1", + `User ${user_id} associated with ${ + user_right_title || user_right_id + } profile`, + "1", + "linkUserAndUserRight" + ) + ); }; -export const checkUserRight = async (req: Request, res: Response): Promise => { - try { - const { user_id, user_right_title } = req.body; +export const checkUserRight = async ( + req: Request, + res: Response +): Promise => { + const { user_id, user_right_id, user_right_title }: any = req.body; - const userHasRight = await CheckUserRightService({ - userProfileToCompare: user_right_title, - userId: user_id - }) + const invalid = invalidProperties(req.body, ["user_id", "user_right_id"]); - return res.status(200).json({ - return_code: "200", - return_msg: "", - user_right_exists: userHasRight ? "1" : "0", - }); - } catch (error) { - if (error instanceof AppError) { - logger.warn(error); - return res.status(error.statusCode).json({ - return_code: String(error.statusCode), - return_msg: error.message, - user_right_exists: "0", - }); - } - return res.status(500).json({ - return_code: "500", - return_msg: "Internal server error", - user_right_exists: "0", - }); + if (invalid) { + return res + .status(400) + .json(response("1", `${invalid}`, "0", "checkUserRight")); } -}; \ No newline at end of file + + if ( + (user_right_id && + !["admin", "user", "supervisor"].includes( + user_right_id?.trim().toLocaleLowerCase() + )) || + (user_right_title && + !["admin", "user", "supervisor"].includes( + user_right_title?.trim().toLocaleLowerCase() + )) + ) { + return res + .status(400) + .json( + response( + "1", + `The user profile ${ + user_right_title || user_right_id + } provided by the property user_right_title or user_right_id does not match the following profiles: admin, user, supervisor`, + "0", + "checkUserRight" + ) + ); + } + + const _user: any = await User.findOne({ + where: { + secondaryId: user_id + } + }); + + if (!_user) + return res + .status(404) + .json(response("1", `User ${user_id} not exist`, "0", "checkUserRight")); + + if ( + (user_right_id && _user.profile != user_right_id) || + (user_right_title && _user.profile != user_right_title) + ) { + return res + .status(403) + .json( + response( + "1", + `User ${user_id} does not have this profile`, + "0", + "checkUserRight" + ) + ); + } + + return res + .status(200) + .json( + response( + "1", + `User ${user_id} has ${user_right_title || user_right_id} profile`, + "1", + "checkUserRight" + ) + ); +}; + +async function logoutUser(userId: any) { + await stopWhoIsOnlineMonitor(); + + let onlineTime = { + userId: `${userId}`, + status: "logout..." + }; + + const io = getIO(); + io.emit("onlineStatus", { + action: "logout", + userOnlineTime: onlineTime + }); + + await startWhoIsOnlineMonitor(); +} + +function response(code: string, msg: string, obj: any, type: string) { + let payload = { return_code: code, return_msg: msg }; + + switch (type) { + case "createUser": + return { ...payload, user_created: obj }; + case "deleteUser": + return { ...payload, user_removed: obj }; + case "listAllUsers": + return { ...payload, user_list: obj }; + case "checkUser": + return { ...payload, user_exists: obj }; + case "updateUser": + return { ...payload, user_updated: obj }; + case "resetPassword": + return { ...payload, password_set: obj }; + case "linkUserAndUserRight": + return { ...payload, user_right_linked: obj }; + case "checkUserRight": + return { ...payload, user_right_exists: obj }; + default: + return payload; + } +} + +function invalidProperties(body: any, pros: any[]) { + for (const field of pros) { + console.log("body[field]: ", body[field], " field: ", field); + if (!body[field]) { + return `${field} is required`; + } + } + return false; +} diff --git a/backend/src/database/migrations/20240315203708-add-secondaryId-to-users.ts b/backend/src/database/migrations/20240315203708-add-secondaryId-to-users.ts new file mode 100644 index 0000000..a2c590e --- /dev/null +++ b/backend/src/database/migrations/20240315203708-add-secondaryId-to-users.ts @@ -0,0 +1,14 @@ +import { QueryInterface, DataTypes } from "sequelize"; + +module.exports = { + up: (queryInterface: QueryInterface) => { + return queryInterface.addColumn("Users", "secondaryId", { + type: DataTypes.STRING, + allowNull: true + }); + }, + + down: (queryInterface: QueryInterface) => { + return queryInterface.removeColumn("Users", "secondaryId"); + } +}; diff --git a/backend/src/middleware/verifyAPIKey.ts b/backend/src/middleware/verifyAPIKey.ts index 5df8481..61cc6f7 100644 --- a/backend/src/middleware/verifyAPIKey.ts +++ b/backend/src/middleware/verifyAPIKey.ts @@ -9,7 +9,7 @@ const verifyAPIKey = (req: Request, res: Response, next: NextFunction): void => const [, token] = authHeader.split(" "); - const apiKeyIsValid = token === process.env.TOKEN_REMOTE_TICKET_CREATION + const apiKeyIsValid = token === process.env.TOKEN_IAM_HORACIUS_EL if (!apiKeyIsValid) { throw new AppError( "Invalid token", diff --git a/backend/src/models/User.ts b/backend/src/models/User.ts index fb2109e..af93cd5 100644 --- a/backend/src/models/User.ts +++ b/backend/src/models/User.ts @@ -41,10 +41,13 @@ class User extends Model { @Default(0) @Column tokenVersion: number; - + @Column positionCompany: string; - + + @Column + secondaryId: string; + @Default("admin") @Column profile: string; @@ -56,9 +59,9 @@ class User extends Model { updatedAt: Date; @HasMany(() => Ticket) tickets: Ticket[]; - + @HasMany(() => UserOnlineTime) - UserOnlineTime: UserOnlineTime[]; + UserOnlineTime: UserOnlineTime[]; @BelongsToMany(() => Queue, () => UserQueue) queues: Queue[]; diff --git a/backend/src/routes/iamRoutesEL.ts b/backend/src/routes/iamRoutesEL.ts index 597b854..2181547 100644 --- a/backend/src/routes/iamRoutesEL.ts +++ b/backend/src/routes/iamRoutesEL.ts @@ -5,15 +5,52 @@ import verifyAPIKey from "../middleware/verifyAPIKey"; const iamRoutesEL = Router(); -iamRoutesEL.post("/IAM/users", verifyAPIKey, IAMControllerEL.createUser); -iamRoutesEL.put("/IAM/users", verifyAPIKey, IAMControllerEL.updateUser); -iamRoutesEL.delete("/IAM/users", verifyAPIKey, IAMControllerEL.deleteUser); -iamRoutesEL.get("/IAM/users/check", verifyAPIKey, IAMControllerEL.checkUser); +iamRoutesEL.post( + "/iam/horacius/createUser", + verifyAPIKey, + IAMControllerEL.createUser +); -iamRoutesEL.patch("/IAM/users/rights/link", verifyAPIKey, IAMControllerEL.linkUserRight); -iamRoutesEL.patch("/IAM/users/rights/unlink", verifyAPIKey, IAMControllerEL.unlinkUserRight); -iamRoutesEL.post("/IAM/users/rights/check", verifyAPIKey, IAMControllerEL.checkUserRight); +iamRoutesEL.put( + "/iam/horacius/updateUser", + verifyAPIKey, + IAMControllerEL.updateUser +); -iamRoutesEL.patch("/IAM/users/reset-password", verifyAPIKey, IAMControllerEL.resetPassword); +iamRoutesEL.delete( + "/iam/horacius/deleteUser", + verifyAPIKey, + IAMControllerEL.deleteUser +); + +iamRoutesEL.get( + "/iam/horacius/listAllUsers", + verifyAPIKey, + IAMControllerEL.listAllUsers +); + +iamRoutesEL.get( + "/iam/horacius/checkUser", + verifyAPIKey, + IAMControllerEL.checkUser +); + +iamRoutesEL.patch( + "/iam/horacius/linkUserAndUserRight", + verifyAPIKey, + IAMControllerEL.linkUserAndUserRight +); + +iamRoutesEL.post( + "/iam/horacius/linkUserAndUserRight", + verifyAPIKey, + IAMControllerEL.checkUserRight +); + +iamRoutesEL.patch( + "/iam/horacius/resetPassword", + verifyAPIKey, + IAMControllerEL.resetPassword +); export default iamRoutesEL; diff --git a/backend/src/services/UserServices/CheckUserRightService.ts b/backend/src/services/UserServices/CheckUserRightService.ts deleted file mode 100644 index 788d630..0000000 --- a/backend/src/services/UserServices/CheckUserRightService.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as Yup from "yup"; -import AppError from "../../errors/AppError"; -import ShowUserService from "./ShowUserService"; - -interface CheckUserRightServiceRequest { - userProfileToCompare: string; - userId: string | number; -} - -type CheckUserRightServiceResponse = boolean; - -const CheckUserRightService = async ({userProfileToCompare, userId}: CheckUserRightServiceRequest): Promise => { - try { - const user = await ShowUserService(userId); - const schema = Yup.object().shape({ - userId: Yup.string().required(), - userProfile: Yup.string().oneOf(['admin', 'user', 'supervisor', 'master']).required() - }); - try { - await schema.validate({ userId, userProfile: userProfileToCompare }); - } catch (err: any) { - throw new AppError(err.message); - } - - return (user.profile == userProfileToCompare) ? true : false - - } catch (error: any) { - console.error('===> Error on CheckUserRightService.ts file: \n', error) - throw new AppError(error.message); - } -}; - -export default CheckUserRightService; diff --git a/backend/src/services/UserServices/CreateUserService.ts b/backend/src/services/UserServices/CreateUserService.ts index 5c6badb..9177289 100644 --- a/backend/src/services/UserServices/CreateUserService.ts +++ b/backend/src/services/UserServices/CreateUserService.ts @@ -11,6 +11,7 @@ interface Request { positionCompany?: string; queueIds?: number[]; profile?: string; + ignoreThrow?: boolean; } interface Response { @@ -27,25 +28,27 @@ const CreateUserService = async ({ name, positionCompany, queueIds = [], - profile = "master" -}: Request): Promise => { - + profile = "master", + ignoreThrow = false +}: Request): Promise => { try { - const schema = Yup.object().shape({ name: Yup.string().required().min(2), - email: Yup.string().required().trim().test( - "Check-email", - "An user with this email already exists.", - async value => { - if (!value) return false; - const emailExists = await User.findOne({ - where: { email: value } - }); - return !emailExists; - } - ), + email: Yup.string() + .required() + .trim() + .test( + "Check-email", + "An user with this email already exists.", + async value => { + if (!value) return false; + const emailExists = await User.findOne({ + where: { email: value } + }); + return !emailExists; + } + ), // email: Yup.string().email().required().test( // "Check-email", @@ -65,6 +68,8 @@ const CreateUserService = async ({ try { await schema.validate({ email, password, name }); } catch (err: any) { + if (ignoreThrow) return { error: true, msg: err.message, status: 400 }; + throw new AppError(err.message); } @@ -86,12 +91,14 @@ const CreateUserService = async ({ const serializedUser = SerializeUser(user); return serializedUser; - } catch (error: any) { - console.error('===> Error on CreateUserService.ts file: \n', error) + console.error("===> Error on CreateUserService.ts file: \n", error); + + if (ignoreThrow) + return { error: true, msg: "Create user error", status: 500 }; + throw new AppError(error.message); } - }; export default CreateUserService; diff --git a/backend/src/services/UserServices/DeleteUserService.ts b/backend/src/services/UserServices/DeleteUserService.ts index 7209cf2..e1e6a2c 100644 --- a/backend/src/services/UserServices/DeleteUserService.ts +++ b/backend/src/services/UserServices/DeleteUserService.ts @@ -2,14 +2,24 @@ import User from "../../models/User"; import AppError from "../../errors/AppError"; import Ticket from "../../models/Ticket"; import UpdateDeletedUserOpenTicketsStatus from "../../helpers/UpdateDeletedUserOpenTicketsStatus"; -import { set } from "../../helpers/RedisClient" +import { set } from "../../helpers/RedisClient"; -const DeleteUserService = async (id: string | number): Promise => { +const DeleteUserService = async ( + id: string | number, + ignoreThrow = false +): Promise => { const user = await User.findOne({ where: { id } }); if (!user) { + if (ignoreThrow) + return { + error: true, + msg: `No user found with this id ${id}`, + status: 404 + }; + throw new AppError("ERR_NO_USER_FOUND", 404); } diff --git a/backend/src/services/UserServices/LinkUserRight.ts b/backend/src/services/UserServices/LinkUserRight.ts deleted file mode 100644 index d34e393..0000000 --- a/backend/src/services/UserServices/LinkUserRight.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as Yup from "yup"; -import AppError from "../../errors/AppError"; -import ShowUserService from "./ShowUserService"; - -interface LinkUserRightServiceRequest { - userProfile: string; - userId: string | number; -} -const LinkUserRightService = async ({userProfile, userId}: LinkUserRightServiceRequest): Promise => { - try { - const user = await ShowUserService(userId); - const schema = Yup.object().shape({ - userId: Yup.string().required(), - userProfile: Yup.string().oneOf(['admin', 'user', 'supervisor']).required() - }); - try { - await schema.validate({ userId, userProfile }); - } catch (err: any) { - throw new AppError(err.message); - } - - await user.update({ - profile: userProfile - }); - - await user.reload(); - } catch (error: any) { - console.error('===> Error on LinkUserRightService.ts file: \n', error) - throw new AppError(error.message); - } -}; - -export default LinkUserRightService; diff --git a/backend/src/services/UserServices/ResetPassword.ts b/backend/src/services/UserServices/ResetPassword.ts deleted file mode 100644 index b396a26..0000000 --- a/backend/src/services/UserServices/ResetPassword.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as Yup from "yup"; -import AppError from "../../errors/AppError"; -import ShowUserService from "./ShowUserService"; - -interface ResetPasswordServiceRequest { - userPassword: string; - userId: string | number; -} -const ResetPasswordService = async ({userPassword, userId}: ResetPasswordServiceRequest): Promise => { - try { - const user = await ShowUserService(userId); - const schema = Yup.object().shape({ - password: Yup.string(), - }); - try { - await schema.validate({ password: userPassword }); - } catch (err: any) { - throw new AppError(err.message); - } - - await user.update({ - userPassword, - }); - - await user.reload(); - } catch (error: any) { - console.error('===> Error on ResetPasswordService.ts file: \n', error) - throw new AppError(error.message); - } -}; - -export default ResetPasswordService; diff --git a/backend/src/services/UserServices/UnlinkUserRight.ts b/backend/src/services/UserServices/UnlinkUserRight.ts deleted file mode 100644 index 13850ac..0000000 --- a/backend/src/services/UserServices/UnlinkUserRight.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as Yup from "yup"; -import AppError from "../../errors/AppError"; -import ShowUserService from "./ShowUserService"; - -interface UnlinkUserRightServiceRequest { - userProfile: string; - userId: string | number; -} -const UnlinkUserRightService = async ({userProfile, userId}: UnlinkUserRightServiceRequest): Promise => { - try { - const user = await ShowUserService(userId); - const schema = Yup.object().shape({ - userId: Yup.string().required(), - userProfile: Yup.string().oneOf(['user']) - }); - try { - await schema.validate({ userId, userProfile }); - } catch (err: any) { - throw new AppError(err.message); - } - - await user.update({ - profile: userProfile || "user" - }); - - await user.reload(); - } catch (error: any) { - console.error('===> Error on UnlinkUserRightService.ts file: \n', error) - throw new AppError(error.message); - } -}; - -export default UnlinkUserRightService; diff --git a/backend/src/services/UserServices/UpdateUserService.ts b/backend/src/services/UserServices/UpdateUserService.ts index 8a0a4ba..329186c 100644 --- a/backend/src/services/UserServices/UpdateUserService.ts +++ b/backend/src/services/UserServices/UpdateUserService.ts @@ -16,6 +16,7 @@ interface UserData { interface Request { userData: UserData; userId: string | number; + ignoreThrow?: boolean; } interface Response { @@ -27,41 +28,53 @@ interface Response { const UpdateUserService = async ({ userData, - userId -}: Request): Promise => { - + userId, + ignoreThrow = false +}: Request): Promise => { try { - const user = await ShowUserService(userId); const schema = Yup.object().shape({ name: Yup.string().min(2), - // email: Yup.string().min(2), + // email: Yup.string().min(2), profile: Yup.string(), password: Yup.string(), - email: Yup.string().trim().required().test( - "Check-email", - "An user with this email already exists.", - async value => { + email: Yup.string() + .trim() + .required() + .test( + "Check-email", + "An user with this email already exists.", + async value => { + if (!value) return false; - if (!value) return false; + const emailExists = await User.findOne({ + where: { email: value }, + raw: true, + attributes: ["email", "id"] + }); - const emailExists = await User.findOne({ where: { email: value }, raw: true, attributes: ['email', 'id'] }); + if (emailExists && user.id != emailExists?.id) { + console.error( + "The email already exists in another user profile!" + ); + return !emailExists; + } - if (emailExists && user.id != emailExists?.id) { - - console.error('The email already exists in another user profile!') - return !emailExists; + return true; } - - return true - } - ), - + ) }); - const { email, password, profile, name, positionCompany, queueIds = [] } = userData; + const { + email, + password, + profile, + name, + positionCompany, + queueIds = [] + } = userData; try { await schema.validate({ email, password, profile, name }); @@ -69,7 +82,6 @@ const UpdateUserService = async ({ throw new AppError(err.message); } - await user.update({ email, password, @@ -91,13 +103,18 @@ const UpdateUserService = async ({ }; return serializedUser; + } catch (err: any) { + console.error("===> Error on UpdateUserService.ts file: \n", err); - } catch (error: any) { - console.error('===> Error on UpdateUserService.ts file: \n', error) - throw new AppError(error.message); + if (ignoreThrow) + return { + error: true, + msg: err.message, + status: 500 + }; + + throw new AppError(err.message); } - - }; export default UpdateUserService;