< Summary

Information
Class: FAU.API.Controllers.UsuariosController
Assembly: FAU.API
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/UsuariosController.cs
Line coverage
80%
Covered lines: 117
Uncovered lines: 29
Coverable lines: 146
Total lines: 323
Line coverage: 80.1%
Branch coverage
67%
Covered branches: 59
Total branches: 88
Branch coverage: 67%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetUsuarios()58.33%151273.68%
GetUsuario()60%1010100%
CreateUsuario()77.27%252282.14%
UpdateUsuario()62.5%432467.74%
CambiarPassword()60%121075%

File(s)

/home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/UsuariosController.cs

#LineLine coverage
 1using FAU.Logica.DTOs;
 2using FAU.Logica.Services;
 3using Microsoft.AspNetCore.Authorization;
 4using Microsoft.AspNetCore.Mvc;
 5
 6namespace FAU.API.Controllers;
 7
 8/// <summary>
 9/// Gestión de usuarios del sistema
 10/// </summary>
 11[ApiController]
 12[Route("api/[controller]")]
 13[Authorize(Roles = "Administrador")]
 14public class UsuariosController : ControllerBase
 15{
 16    private readonly IUsuarioService _usuarioService;
 17    private readonly ILogger<UsuariosController> _logger;
 18
 1519    public UsuariosController(
 1520        IUsuarioService usuarioService,
 1521        ILogger<UsuariosController> logger)
 22    {
 1523        _usuarioService = usuarioService;
 1524        _logger = logger;
 1525    }
 26
 27    /// <summary>
 28    /// Listar usuarios con filtros y paginación
 29    /// GET /api/usuarios?rolId=&estado=&q=&page=1&pageSize=25
 30    /// </summary>
 31    [HttpGet]
 32    public async Task<IActionResult> GetUsuarios(
 33        [FromQuery] long? rolId,
 34        [FromQuery] string? estado,
 35        [FromQuery] string? q,
 36        [FromQuery] int page = 1,
 37        [FromQuery] int pageSize = 25)
 38    {
 39        try
 40        {
 41            // Validación de parámetros
 442            if (page < 1) page = 1;
 443            if (pageSize < 1) pageSize = 25;
 444            if (pageSize > 100) pageSize = 100; // Límite máximo
 45
 446            var usuarios = await _usuarioService.GetAllAsync();
 47
 48            // Aplicar filtros
 349            var query = usuarios.AsQueryable();
 50
 351            if (rolId.HasValue)
 52            {
 153                query = query.Where(u => u.Roles.Any(r => r.Id == rolId.Value));
 54            }
 55
 356            if (!string.IsNullOrWhiteSpace(estado))
 57            {
 058                query = query.Where(u => u.Estado.Equals(estado, StringComparison.OrdinalIgnoreCase));
 59            }
 60
 361            if (!string.IsNullOrWhiteSpace(q))
 62            {
 063                var searchTerm = q.ToLower();
 064                query = query.Where(u =>
 065                    u.Username.ToLower().Contains(searchTerm) ||
 066                    (u.Persona != null && (
 067                        u.Persona.Nombre.ToLower().Contains(searchTerm) ||
 068                        u.Persona.Apellido.ToLower().Contains(searchTerm) ||
 069                        (u.Persona.Email != null && u.Persona.Email.ToLower().Contains(searchTerm))
 070                    ))
 071                );
 72            }
 73
 374            var total = query.Count();
 75
 76            // Paginación
 377            var usuariosPaginados = query
 378                .Skip((page - 1) * pageSize)
 379                .Take(pageSize)
 380                .ToList()
 1381                .Select(u => new
 1382                {
 1383                    id = u.Id,
 1384                    usuario = u.Username,
 1385                    nombre = u.Persona != null ? $"{u.Persona.Nombre} {u.Persona.Apellido}" : "",
 1386                    email = u.Persona?.Email ?? "",
 1387                    rol = u.Roles.FirstOrDefault()?.Nombre ?? "",
 1388                    estado = u.Estado,
 1389                    ultimoAcceso = u.FechaActualizacion
 1390                })
 391                .ToList();
 92
 393            var response = new
 394            {
 395                items = usuariosPaginados,
 396                total = total,
 397                page = page,
 398                pageSize = pageSize,
 399                totalPages = (int)Math.Ceiling((double)total / pageSize)
 3100            };
 101
 3102            return Ok(ApiResponse<object>.SuccessResult(response));
 103        }
 1104        catch (Exception ex)
 105        {
 1106            _logger.LogError(ex, "Error al obtener usuarios");
 1107            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 108        }
 4109    }
 110
 111    /// <summary>
 112    /// Obtener detalle de usuario por ID
 113    /// GET /api/usuarios/{id}
 114    /// </summary>
 115    [HttpGet("{id}")]
 116    public async Task<IActionResult> GetUsuario(long id)
 117    {
 118        try
 119        {
 3120            var usuario = await _usuarioService.GetByIdAsync(id);
 121
 2122            if (usuario == null)
 123            {
 1124                return NotFound(ApiResponse<string>.ErrorResult("Usuario no encontrado"));
 125            }
 126
 1127            var response = new
 1128            {
 1129                id = usuario.Id,
 1130                usuario = usuario.Username,
 1131                nombre = usuario.Persona != null ? $"{usuario.Persona.Nombre} {usuario.Persona.Apellido}" : "",
 1132                email = usuario.Persona?.Email ?? "",
 1133                rolId = usuario.Roles.FirstOrDefault()?.Id,
 1134                estado = usuario.Estado
 1135            };
 136
 1137            return Ok(ApiResponse<object>.SuccessResult(response));
 138        }
 1139        catch (Exception ex)
 140        {
 1141            _logger.LogError(ex, "Error al obtener usuario {Id}", id);
 1142            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 143        }
 3144    }
 145
 146    /// <summary>
 147    /// Crear usuario con contraseña temporal
 148    /// POST /api/usuarios
 149    /// </summary>
 150    [HttpPost]
 151    public async Task<IActionResult> CreateUsuario([FromBody] CreateUsuarioRequest request)
 152    {
 153        try
 154        {
 155            // Validaciones
 3156            if (string.IsNullOrWhiteSpace(request.Username))
 157            {
 1158                return BadRequest(ApiResponse<string>.ErrorResult("El nombre de usuario es requerido"));
 159            }
 160
 2161            if (string.IsNullOrWhiteSpace(request.Password))
 162            {
 0163                return BadRequest(ApiResponse<string>.ErrorResult("La contraseña es requerida"));
 164            }
 165
 2166            var (success, usuario, error) = await _usuarioService.CreateAsync(
 2167                request.Username,
 2168                request.Password,
 2169                request.PersonaId);
 170
 2171            if (!success)
 172            {
 1173                if (error?.Contains("ya existe") == true || error?.Contains("ya está en uso") == true)
 174                {
 1175                    return Conflict(ApiResponse<string>.ErrorResult(error));
 176                }
 0177                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error al crear usuario"));
 178            }
 179
 180            // Asignar roles si se especificaron
 1181            if (request.RolesIds != null && request.RolesIds.Any())
 182            {
 4183                foreach (var rolId in request.RolesIds)
 184                {
 1185                    await _usuarioService.AsignarRolAsync(usuario!.Id, rolId);
 186                }
 187            }
 188
 1189            var response = new
 1190            {
 1191                id = usuario!.Id,
 1192                creado = true
 1193            };
 194
 1195            return CreatedAtAction(
 1196                nameof(GetUsuario),
 1197                new { id = usuario.Id },
 1198                ApiResponse<object>.SuccessResult(response, "Usuario creado exitosamente"));
 199        }
 0200        catch (Exception ex)
 201        {
 0202            _logger.LogError(ex, "Error al crear usuario");
 0203            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 204        }
 3205    }
 206
 207    /// <summary>
 208    /// Editar usuario (incluye activar/bloquear mediante campo estado)
 209    /// PUT /api/usuarios/{id}
 210    /// </summary>
 211    [HttpPut("{id}")]
 212    public async Task<IActionResult> UpdateUsuario(long id, [FromBody] UpdateUsuarioRequest request)
 213    {
 214        try
 215        {
 2216            var usuario = await _usuarioService.GetByIdAsync(id);
 2217            if (usuario == null)
 218            {
 1219                return NotFound(ApiResponse<string>.ErrorResult("Usuario no encontrado"));
 220            }
 221
 222            // Actualizar datos de persona si se proporcionan
 1223            if (usuario.Persona != null)
 224            {
 1225                if (!string.IsNullOrWhiteSpace(request.Nombre))
 226                {
 227                    // Asumiendo que nombre viene como "Nombre Apellido"
 1228                    var nombres = request.Nombre.Split(' ', 2);
 1229                    usuario.Persona.Nombre = nombres[0];
 1230                    if (nombres.Length > 1)
 231                    {
 1232                        usuario.Persona.Apellido = nombres[1];
 233                    }
 234                }
 235
 1236                if (!string.IsNullOrWhiteSpace(request.Email))
 237                {
 1238                    usuario.Persona.Email = request.Email;
 239                }
 240            }
 241
 242            // Cambiar rol si se especifica
 1243            if (request.RolId.HasValue)
 244            {
 245                // Remover roles actuales
 0246                var rolesActuales = usuario.Roles.ToList();
 0247                foreach (var rol in rolesActuales)
 248                {
 0249                    await _usuarioService.RemoverRolAsync(id, rol.Id);
 250                }
 251
 252                // Asignar nuevo rol
 0253                var (successRol, errorRol) = await _usuarioService.AsignarRolAsync(id, request.RolId.Value);
 0254                if (!successRol)
 255                {
 0256                    return BadRequest(ApiResponse<string>.ErrorResult(errorRol ?? "Error al asignar rol"));
 257                }
 258            }
 259
 260            // Cambiar estado si se especifica
 1261            if (!string.IsNullOrWhiteSpace(request.Estado))
 262            {
 1263                var (successEstado, errorEstado) = await _usuarioService.CambiarEstadoAsync(id, request.Estado);
 1264                if (!successEstado)
 265                {
 0266                    return BadRequest(ApiResponse<string>.ErrorResult(errorEstado ?? "Error al cambiar estado"));
 267                }
 268            }
 269
 1270            var response = new
 1271            {
 1272                actualizado = true
 1273            };
 274
 1275            return Ok(ApiResponse<object>.SuccessResult(response, "Usuario actualizado exitosamente"));
 276        }
 0277        catch (Exception ex)
 278        {
 0279            _logger.LogError(ex, "Error al actualizar usuario {Id}", id);
 0280            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 281        }
 2282    }
 283
 284    /// <summary>
 285    /// Cambiar contraseña de usuario (también para reset)
 286    /// PATCH /api/usuarios/{id}/password
 287    /// </summary>
 288    [HttpPatch("{id}/password")]
 289    public async Task<IActionResult> CambiarPassword(long id, [FromBody] CambiarPasswordRequest request)
 290    {
 291        try
 292        {
 3293            if (string.IsNullOrWhiteSpace(request.NuevaPassword))
 294            {
 1295                return BadRequest(ApiResponse<string>.ErrorResult("La nueva contraseña es requerida"));
 296            }
 297
 2298            var (success, error) = await _usuarioService.CambiarPasswordAsync(id, request.NuevaPassword);
 299
 2300            if (!success)
 301            {
 1302                if (error?.Contains("no encontrado") == true)
 303                {
 1304                    return NotFound(ApiResponse<string>.ErrorResult(error));
 305                }
 0306                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error al cambiar contraseña"));
 307            }
 308
 1309            var response = new
 1310            {
 1311                actualizado = true
 1312            };
 313
 1314            return Ok(ApiResponse<object>.SuccessResult(response, "Contraseña actualizada exitosamente"));
 315        }
 0316        catch (Exception ex)
 317        {
 0318            _logger.LogError(ex, "Error al cambiar contraseña del usuario {Id}", id);
 0319            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 320        }
 3321    }
 322}
 323