"use strict"; /** * UsersService - Gestión de usuarios * * CRUD de usuarios con soporte multi-tenant y RBAC. * * @module Users */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.UsersService = void 0; const typeorm_1 = require("typeorm"); const bcrypt = __importStar(require("bcryptjs")); class UsersService { userRepository; roleRepository; userRoleRepository; constructor(userRepository, roleRepository, userRoleRepository) { this.userRepository = userRepository; this.roleRepository = roleRepository; this.userRoleRepository = userRoleRepository; } /** * Listar usuarios de un tenant */ async findAll(options) { const { tenantId, page = 1, limit = 20, search, isActive } = options; const query = this.userRepository .createQueryBuilder('user') .leftJoinAndSelect('user.tenant', 'tenant') .where('user.tenant_id = :tenantId', { tenantId }) .andWhere('user.deleted_at IS NULL'); if (search) { query.andWhere('(user.email ILIKE :search OR user.first_name ILIKE :search OR user.last_name ILIKE :search)', { search: `%${search}%` }); } if (isActive !== undefined) { query.andWhere('user.is_active = :isActive', { isActive }); } const total = await query.getCount(); const users = await query .skip((page - 1) * limit) .take(limit) .orderBy('user.created_at', 'DESC') .getMany(); return { users, total }; } /** * Obtener usuario por ID */ async findById(id, tenantId) { return this.userRepository.findOne({ where: { id, tenantId, deletedAt: (0, typeorm_1.IsNull)() }, relations: ['tenant'], }); } /** * Obtener usuario por email */ async findByEmail(email, tenantId) { return this.userRepository.findOne({ where: { email, tenantId, deletedAt: (0, typeorm_1.IsNull)() }, }); } /** * Crear usuario */ async create(dto, createdBy) { // Verificar email único en tenant const existing = await this.findByEmail(dto.email, dto.tenantId); if (existing) { throw new Error('Email already exists in this tenant'); } const passwordHash = await bcrypt.hash(dto.password, 12); const user = await this.userRepository.save(this.userRepository.create({ email: dto.email, passwordHash, firstName: dto.firstName, lastName: dto.lastName, tenantId: dto.tenantId, defaultTenantId: dto.tenantId, isActive: true, roles: dto.roles || ['viewer'], })); // Asignar roles si se especificaron if (dto.roles && dto.roles.length > 0) { for (const roleCode of dto.roles) { await this.assignRole({ userId: user.id, roleCode, tenantId: dto.tenantId }, createdBy); } } return user; } /** * Actualizar usuario */ async update(id, tenantId, dto) { const user = await this.findById(id, tenantId); if (!user) { throw new Error('User not found'); } await this.userRepository.update(id, { ...dto, updatedAt: new Date(), }); return this.findById(id, tenantId); } /** * Soft delete de usuario */ async delete(id, tenantId, _deletedBy) { const user = await this.findById(id, tenantId); if (!user) { throw new Error('User not found'); } await this.userRepository.update(id, { deletedAt: new Date(), isActive: false, }); } /** * Activar/Desactivar usuario */ async setActive(id, tenantId, isActive) { const user = await this.findById(id, tenantId); if (!user) { throw new Error('User not found'); } await this.userRepository.update(id, { isActive }); return this.findById(id, tenantId); } /** * Asignar rol a usuario */ async assignRole(dto, assignedBy) { const role = await this.roleRepository.findOne({ where: { code: dto.roleCode, isActive: true }, }); if (!role) { throw new Error('Role not found'); } // Verificar si ya tiene el rol const existing = await this.userRoleRepository.findOne({ where: { userId: dto.userId, roleId: role.id, tenantId: dto.tenantId }, }); if (existing) { return existing; } return this.userRoleRepository.save(this.userRoleRepository.create({ userId: dto.userId, roleId: role.id, tenantId: dto.tenantId, assignedBy, })); } /** * Remover rol de usuario */ async removeRole(userId, roleCode, tenantId) { const role = await this.roleRepository.findOne({ where: { code: roleCode }, }); if (!role) { throw new Error('Role not found'); } await this.userRoleRepository.delete({ userId, roleId: role.id, tenantId, }); } /** * Obtener roles de usuario */ async getUserRoles(userId, tenantId) { const userRoles = await this.userRoleRepository.find({ where: { userId, tenantId }, relations: ['role'], }); return userRoles.map((ur) => ur.role); } /** * Listar todos los roles disponibles */ async listRoles() { return this.roleRepository.find({ where: { isActive: true }, order: { name: 'ASC' }, }); } } exports.UsersService = UsersService; //# sourceMappingURL=users.service.js.map