From 9099a781a14eeb31241c3f665c8142b033a94d98 Mon Sep 17 00:00:00 2001 From: karol Date: Fri, 10 Jul 2026 15:16:14 +0000 Subject: [PATCH] =?UTF-8?q?Actualizaci=C3=B3n=20m=C3=B3dulo=20de=20usuario?= =?UTF-8?q?s=20e=20implementaci=C3=B3n=20de=20m=C3=B3dulo=20catalogs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/config/mongodb.ts | 15 +- backend/src/config/sqlserver.ts | 42 +-- .../modules/catalogs/catalog.controller.ts | 248 ++++++++++++++++++ .../src/modules/catalogs/catalog.routes.ts | 41 +++ .../src/modules/catalogs/catalog.service.ts | 173 ++++++++++++ backend/src/modules/user/user.controller.ts | 10 +- backend/src/modules/user/user.model.ts | 1 + backend/src/modules/user/user.routes.ts | 12 +- backend/src/modules/user/user.service.ts | 77 ++++++ backend/src/server.ts | 29 +- 10 files changed, 593 insertions(+), 55 deletions(-) create mode 100644 backend/src/modules/catalogs/catalog.controller.ts create mode 100644 backend/src/modules/catalogs/catalog.routes.ts create mode 100644 backend/src/modules/catalogs/catalog.service.ts diff --git a/backend/src/config/mongodb.ts b/backend/src/config/mongodb.ts index 0eab675..d81a00c 100644 --- a/backend/src/config/mongodb.ts +++ b/backend/src/config/mongodb.ts @@ -1,18 +1,21 @@ import mongoose from "mongoose"; -export const connectMongo = async (): Promise => { +export const connectMongo = async () => { try { - await mongoose.connect(process.env.MONGO_URI!); - console.log("MongoDB conectado"); + await mongoose.connect( + process.env.MONGO_URI! + ); + + console.log( + "MongoDB conectado" + ); } catch(error){ - console.error("Error MongoDB", error); + console.error(error); process.exit(1); - } - }; \ No newline at end of file diff --git a/backend/src/config/sqlserver.ts b/backend/src/config/sqlserver.ts index 5e330b5..a249305 100644 --- a/backend/src/config/sqlserver.ts +++ b/backend/src/config/sqlserver.ts @@ -1,30 +1,30 @@ -/*import sql from "mssql"; +import sql from "mssql"; +const config = { -const sqlConfig:sql.config = { - user: process.env.SQL_USER, - password: process.env.SQL_PASSWORD, - server:process.env.SQL_SERVER!, - database:process.env.SQL_DATABASE, - options:{ - trustServerCertificate:true, - encrypt:false + password: process.env.SQL_PASSWORD, + + server: process.env.SQL_SERVER!, + + database: process.env.SQL_DATABASE!, + + options: { + + trustServerCertificate: true } }; - -export const connectSqlServer = async() => { - - try{ - await sql.connect(sqlConfig); - console.log("SQL Server Conectado"); - - }catch(error){ - console.error("Error SQL Server", error); - +export async function getConnection(){ + try { + const pool = await sql.connect(config); + return pool; + }catch(error) { + console.error("Error al conectar con SQLServer", error); + + throw error; + } - -};*/ +} diff --git a/backend/src/modules/catalogs/catalog.controller.ts b/backend/src/modules/catalogs/catalog.controller.ts new file mode 100644 index 0000000..251688f --- /dev/null +++ b/backend/src/modules/catalogs/catalog.controller.ts @@ -0,0 +1,248 @@ +import { Request, Response } from "express"; +import { CatalogService } from "./catalog.service"; + +const service = new CatalogService(); + +export class CatalogController { + + //Obtener todos los empleados + + async getEmployees( + req: Request, + res: Response + ) { + + try { + + const employees = + await service.getEmployees(); + + res.json(employees); + + } catch (error) { + + res.status(500).json({ + message: "Error al obtener empleados", + error + }); + + } + + } + + //Obtener empleado por ID + + async getEmployeeById( + req: Request, + res: Response + ) { + + try { + + const employee = + await service.getEmployeeById( + Number(req.params.id) + ); + + if (!employee) { + + return res.status(404).json({ + message: "Empleado no encontrado" + }); + + } + + res.json(employee); + + } catch (error) { + + res.status(500).json({ + message: "Error al obtener empleado", + error + }); + + } + + } + + //Obtener todos los vehículos + + async getVehicles( + req: Request, + res: Response + ) { + + try { + + const vehicles = + await service.getVehicles(); + + res.json(vehicles); + + } catch (error) { + + res.status(500).json({ + message: "Error al obtener vehículos", + error + }); + + } + + } + + //Obtener vehículo por ID + + async getVehicleById( + req: Request, + res: Response + ) { + + try { + + const vehicle = + await service.getVehicleById( + Number(req.params.id) + ); + + if (!vehicle) { + + return res.status(404).json({ + message: "Vehículo no encontrado" + }); + + } + + res.json(vehicle); + + } catch (error) { + + res.status(500).json({ + message: "Error al obtener vehículo", + error + }); + + } + + } + + //Obtener todos los departamentos + + async getDepartments( + req: Request, + res: Response + ) { + + try { + + const departments = + await service.getDepartments(); + + res.json(departments); + + } catch (error) { + + res.status(500).json({ + message: "Error al obtener departamentos", + error + }); + + } + + } + + //Obtener departamento por ID + + async getDepartmentById( + req: Request, + res: Response + ) { + + try { + + const department = + await service.getDepartmentById( + Number(req.params.id) + ); + + if (!department) { + + return res.status(404).json({ + message: "Departamento no encontrado" + }); + + } + + res.json(department); + + } catch (error) { + + res.status(500).json({ + message: "Error al obtener departamento", + error + }); + + } + + } + + //Obtener todas las rutas + + async getRoutes( + req: Request, + res: Response + ) { + + try { + + const routes = + await service.getRoutes(); + + res.json(routes); + + } catch (error) { + + res.status(500).json({ + message: "Error al obtener rutas", + error + }); + + } + + } + + //Obtener ruta por ID + + async getRouteById( + req: Request, + res: Response + ) { + + try { + + const route = + await service.getRouteById( + Number(req.params.id) + ); + + if (!route) { + + return res.status(404).json({ + message: "Ruta no encontrada" + }); + + } + + res.json(route); + + } catch (error) { + + res.status(500).json({ + message: "Error al obtener ruta", + error + }); + + } + + } + +} \ No newline at end of file diff --git a/backend/src/modules/catalogs/catalog.routes.ts b/backend/src/modules/catalogs/catalog.routes.ts new file mode 100644 index 0000000..7f69bab --- /dev/null +++ b/backend/src/modules/catalogs/catalog.routes.ts @@ -0,0 +1,41 @@ +import { Router } from "express"; +import { CatalogController } from "./catalog.controller"; + +import { authMiddleware } from "../auth/auth.middleware"; +import { permissionMiddleware } from "../auth/permission.middleware"; + +const catalogRouter = Router(); + +const controller = new CatalogController(); + +//EMPLEADOS +// Obtener todos los empleados +catalogRouter.get("/employees", authMiddleware, permissionMiddleware("catalogs", "read"), controller.getEmployees); + +// Obtener empleado por ID +catalogRouter.get("/employees/:id", authMiddleware, permissionMiddleware("catalogs", "read"), controller.getEmployeeById); + + +//VEHÍCULOS +// Obtener todos los vehículos +catalogRouter.get("/vehicles", authMiddleware, permissionMiddleware("catalogs", "read"), controller.getVehicles); + +// Obtener vehículo por ID +catalogRouter.get("/vehicles/:id", authMiddleware, permissionMiddleware("catalogs", "read"), controller.getVehicleById); + + +//DEPARTAMENTOS +// Obtener todos los departamentos +catalogRouter.get("/departments", authMiddleware, permissionMiddleware("catalogs", "read"), controller.getDepartments); + +// Obtener departamento por ID +catalogRouter.get("/departments/:id", authMiddleware, permissionMiddleware("catalogs", "read"), controller.getDepartmentById); + +// RUTAS +// Obtener todas las rutas +catalogRouter.get("/routes", authMiddleware, permissionMiddleware("catalogs", "read"), controller.getRoutes); + +// Obtener ruta por ID +catalogRouter.get("/routes/:id", authMiddleware, permissionMiddleware("catalogs", "read"), controller.getRouteById); + +export default catalogRouter; \ No newline at end of file diff --git a/backend/src/modules/catalogs/catalog.service.ts b/backend/src/modules/catalogs/catalog.service.ts new file mode 100644 index 0000000..87898f7 --- /dev/null +++ b/backend/src/modules/catalogs/catalog.service.ts @@ -0,0 +1,173 @@ +import { getConnection } from "../../config/sqlserver"; + +export class CatalogService { + + //Obtener todos los empleados + + async getEmployees() { + + const pool = await getConnection(); + + const result = await pool + .request() + .query(` + SELECT * + FROM vw_Empleados + ORDER BY id_empleado + `); + + return result.recordset; + + } + + //Obtener un empleado por código + + async getEmployeeById( + employeeId: number + ) { + + const pool = await getConnection(); + + const result = await pool + .request() + .input( + "id_empleado", + employeeId + ) + .query(` + SELECT * + FROM vw_Empleados + WHERE id_empleado = @id_empleado + `); + + return result.recordset[0]; + + } + + //Obtener todos los vehículos + + async getVehicles() { + + const pool = await getConnection(); + + const result = await pool + .request() + .query(` + SELECT * + FROM vw_Vehiculos + ORDER BY id_vehiculo + `); + + return result.recordset; + + } + + //Obtener vehículo por código + + async getVehicleById( + vehicleId: number + ) { + + const pool = await getConnection(); + + const result = await pool + .request() + .input( + "id_vehiculo", + vehicleId + ) + .query(` + SELECT * + FROM vw_Vehiculos + WHERE id_vehiculo = @id_vehiculo + `); + + return result.recordset[0]; + + } + + //Obtener departamentos + + async getDepartments() { + + const pool = await getConnection(); + + const result = await pool + .request() + .query(` + SELECT * + FROM vw_Departamentos + ORDER BY id_departamento + `); + + return result.recordset; + + } + + //Obtener departamento por código + + async getDepartmentById( + departmentId: number + ) { + + const pool = await getConnection(); + + const result = await pool + .request() + .input( + "id_departamento", + departmentId + ) + .query(` + SELECT * + FROM vw_Departamentos + WHERE id_departamento = @id_departamento + `); + + return result.recordset[0]; + + } + + //Obtener rutas + + async getRoutes() { + + const pool = await getConnection(); + + const result = await pool + .request() + .query(` + SELECT * + FROM vw_Rutas + ORDER BY id_ruta + `); + + return result.recordset; + + } + + //Obtener ruta por código + + async getRouteById( + routeId: number + ) { + + const pool = await getConnection(); + + const result = await pool + .request() + .input( + "id_ruta", + routeId + ) + .query(` + SELECT * + FROM vw_Rutas + WHERE id_ruta = @id_ruta + `); + + return result.recordset[0]; + + } + +} \ No newline at end of file diff --git a/backend/src/modules/user/user.controller.ts b/backend/src/modules/user/user.controller.ts index f624729..2cccf33 100644 --- a/backend/src/modules/user/user.controller.ts +++ b/backend/src/modules/user/user.controller.ts @@ -54,15 +54,14 @@ export class UserController { res:Response ) { try { - const user = - await userService.create( + const user = await userService.create( req.body ); res.status(201).json(user); - }catch(error){ + }catch (error:any) { res.status(500).json({ - message:"Error al crear usuario", + message: error.message, error }); @@ -119,6 +118,5 @@ export class UserController { error }); } - } - + } } \ No newline at end of file diff --git a/backend/src/modules/user/user.model.ts b/backend/src/modules/user/user.model.ts index 71d1de5..fa0a60b 100644 --- a/backend/src/modules/user/user.model.ts +++ b/backend/src/modules/user/user.model.ts @@ -13,6 +13,7 @@ const userSchema = new mongoose.Schema({ type:String, required:true, unique:true, + trim:true }, passwordHash:{ diff --git a/backend/src/modules/user/user.routes.ts b/backend/src/modules/user/user.routes.ts index d1e1943..f028be1 100644 --- a/backend/src/modules/user/user.routes.ts +++ b/backend/src/modules/user/user.routes.ts @@ -1,20 +1,22 @@ import { Router } from "express"; import { UserController } from "./user.controller"; + import { authMiddleware } from "../auth/auth.middleware"; +import { permissionMiddleware } from "../auth/permission.middleware"; const userRouter = Router(); const controller = new UserController(); -userRouter.get("/", authMiddleware, controller.getAll); +userRouter.get("/", authMiddleware, permissionMiddleware("users", "read"), controller.getAll); -userRouter.get("/:id", authMiddleware, controller.getById); +userRouter.get("/:id", authMiddleware, permissionMiddleware("users", "read"), controller.getById); -userRouter.post("/", controller.create); +userRouter.post("/", authMiddleware, permissionMiddleware("users", "create"), controller.create); -userRouter.put("/:id", authMiddleware, controller.update); +userRouter.put("/:id", authMiddleware, permissionMiddleware("users", "update"), controller.update); -userRouter.delete("/:id", authMiddleware, controller.delete); +userRouter.delete("/:id", authMiddleware, permissionMiddleware("users", "delete"), controller.delete); export default userRouter; \ No newline at end of file diff --git a/backend/src/modules/user/user.service.ts b/backend/src/modules/user/user.service.ts index 63051e5..2d8cde1 100644 --- a/backend/src/modules/user/user.service.ts +++ b/backend/src/modules/user/user.service.ts @@ -1,6 +1,9 @@ import bcrypt from "bcrypt"; import userModel from "./user.model"; import { IUser } from "./user.interface"; +import { CatalogService } from "../catalogs/catalog.service"; + +const catalogService = new CatalogService(); export class UserService { @@ -22,6 +25,33 @@ export class UserService { async create( data:IUser ) { + //Validar que el empleado exista + const employee = await catalogService.getEmployeeById( + data.employeeId + ); + + if(!employee){ + throw new Error( "El empleado no existe.") + } + + //Validar que el empelado no tenga usuario + const employeeExist = await userModel.findOne({ + employeeId:data.employeeId + }); + + if(employeeExist){ + throw new Error ("El empleado ya tiene usuario registrado"); + } + + //Validar nombre de usuario + const userNameExist = await userModel.findOne({ + userName:data.userName + }); + + if(userNameExist){ + throw new Error("El nombre del usuario ya existe"); + } + const passwordHash = await bcrypt.hash( data.passwordHash, 10 @@ -36,6 +66,53 @@ export class UserService { id:string, data:Partial ) { + + const user = await userModel.findById(id); + + if (!user) { + return null; + } + + // Validar empleado + if (data.employeeId !== undefined) { + + const employee = await catalogService.getEmployeeById( + data.employeeId + ); + + if (!employee) { + throw new Error("El empleado no existe."); + } + + const employeeExists = + await userModel.findOne({ + employeeId: data.employeeId, + _id: { $ne: id } + }); + + if (employeeExists) { + throw new Error( + "El empleado ya tiene un usuario registrado." + ); + } + + } + + // Validar nombre de usuario + if (data.userName !== undefined) { + + const userNameExists = + await userModel.findOne({ + userName: data.userName, + _id: { $ne: id } + }); + + if (userNameExists) { + throw new Error("El nombre de usuario ya existe."); + } + + } + if(data.passwordHash){ data.passwordHash = await bcrypt.hash( data.passwordHash, diff --git a/backend/src/server.ts b/backend/src/server.ts index 90ee09f..9f617d0 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -2,30 +2,25 @@ import dotenv from "dotenv"; dotenv.config(); -import { connectMongo } from "./config/mongodb"; -//import { connectSqlServer } from "./config/sqlserver"; import app from "./app"; -const PORT = process.env.PORT || 5000; - -const startServer = async() => { - - try { - - await connectMongo(); - //await connectSqlServer(); +import { connectMongo } from "./config/mongodb"; - app.listen(PORT, () => { +const startServer = +async () => { - console.log(`Servidor ejecutandose en puerto ${PORT}`); - }); - - }catch(error){ + await connectMongo(); - console.error("Error al iniciar el servidor", error); - } + app.listen( + process.env.PORT, + () => { + console.log( + `Servidor iniciado en puerto ${process.env.PORT}` + ); + } + ); }; startServer(); \ No newline at end of file