erp-construccion-backend/dist/modules/users/services/users.service.js

223 lines
7.1 KiB
JavaScript

"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