Files
FRASA-CAS/api-gateway/src/controllers/usuarios.controller.ts
Consult AS Technology b2634f97ab feat(config): modulo Configuraciones admin + permisos por rol
- Tablas ConfiguracionSistema (7 configs) + RolConfiguracion (6 roles)
- Endpoints: config/sistema GET/PATCH, config/roles GET/PATCH,
  config/usuarios GET/PATCH, config/reset-roles POST, config/acciones GET
- modulosDeRol() async con fallback a MATRIZ estatica
- auth/me devuelve acciones[] segun rol del usuario
- saludMonday.estaDisponible() lee modo_local_forzado de DB (cache 30s)
- Landing: vista Configuraciones con 4 tabs (Modo, Roles, Usuarios, Sistema)
- Mi-dia: boton Descartar se deshabilita si !descartar_lead
- 630 API tests + 24 landing tests + 20 mi-dia tests verdes

Seed: npm run seed:config
2026-09-06 09:46:19 +00:00

70 lines
2.6 KiB
TypeScript

import type { Request, Response } from 'express'
import { z } from 'zod'
import { mondayService } from '../services/monday.service.js'
import { prisma } from '../services/prisma.js'
import { aPublico } from '../services/auth.service.js'
import { esRolValido } from '../config/roles.js'
import { AppError, BadRequestError } from '../utils/errors.js'
/**
* Vínculo usuario del ecosistema ↔ usuario de Monday (people). Es el mapeo
* que alimenta round-robin, mis-leads, actividades y alertas; el usuario lo
* elige él mismo desde la landing (Configuración de cuenta).
*/
/** GET /api/monday/usuarios (Bearer) → usuarios activos del workspace */
export async function listarUsuariosMondayEndpoint(_req: Request, res: Response): Promise<void> {
const usuarios = await mondayService.getUsuariosWorkspace()
res.json(usuarios.map((u) => ({ id: u.id, nombre: u.nombre, email: u.email })))
}
const vinculoMondaySchema = z.object({
mondayUserId: z.number().int().positive().nullable(),
})
/**
* PATCH /api/usuarios/me/monday (Bearer) { mondayUserId: number | null }
* null desvincula. Un id que no existe en el workspace → 400.
*/
export async function actualizarVinculoMondayEndpoint(req: Request, res: Response): Promise<void> {
if (!req.usuarioToken) throw new BadRequestError('Falta el token verificado')
const { mondayUserId } = vinculoMondaySchema.parse(req.body)
if (mondayUserId !== null) {
const usuarios = await mondayService.getUsuariosWorkspace()
if (!usuarios.some((u) => u.id === mondayUserId)) {
throw new BadRequestError(`El usuario de Monday ${mondayUserId} no existe en el workspace`)
}
}
const usuario = await prisma.usuario.update({
where: { id: req.usuarioToken.sub },
data: { mondayUserId },
})
res.json(await aPublico(usuario))
}
const cambiarRolSchema = z.object({
rol: z.string().min(1),
})
/**
* PATCH /api/usuarios/:id/rol (Bearer, solo admin) { rol } → usuario público
* actualizado. Solo roles de la matriz nueva (config/roles.ts); los legacy
* ('coordinador', 'corporativo') ya no se asignan.
*/
export async function actualizarRolEndpoint(req: Request, res: Response): Promise<void> {
if (!req.usuarioToken) throw new BadRequestError('Falta el token verificado')
if (req.usuarioToken.rol !== 'admin') {
throw new AppError(403, 'Solo un administrador puede cambiar roles')
}
const { rol } = cambiarRolSchema.parse(req.body)
if (!esRolValido(rol)) throw new BadRequestError(`Rol inválido: ${rol}`)
const usuario = await prisma.usuario.update({
where: { id: req.params.id as string },
data: { rol },
})
res.json(await aPublico(usuario))
}