< 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
91%
Covered lines: 136
Uncovered lines: 12
Coverable lines: 148
Total lines: 325
Line coverage: 91.8%
Branch coverage
71%
Covered branches: 63
Total branches: 88
Branch coverage: 71.5%
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()75%1212100%
GetUsuario()60%1010100%
CreateUsuario()77.27%252282.14%
UpdateUsuario()70.83%282480.64%
CambiarPassword()60%101093.75%

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
 2019    public UsuariosController(
 2020        IUsuarioService usuarioService,
 2021        ILogger<UsuariosController> logger)
 22    {
 2023        _usuarioService = usuarioService;
 2024        _logger = logger;
 2025    }
 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
 642            if (page < 1) page = 1;
 643            if (pageSize < 1) pageSize = 25;
 644            if (pageSize > 100) pageSize = 100; // Límite máximo
 45
 646            var usuarios = await _usuarioService.GetAllAsync();
 47
 48            // Aplicar filtros
 549            var query = usuarios.AsQueryable();
 50
 551            if (rolId.HasValue)
 52            {
 153                query = query.Where(u => u.Roles.Any(r => r.Id == rolId.Value));
 54            }
 55
 556            if (!string.IsNullOrWhiteSpace(estado))
 57            {
 158                query = query.Where(u => u.Estado.Equals(estado, StringComparison.OrdinalIgnoreCase));
 59            }
 60
 561            if (!string.IsNullOrWhiteSpace(q))
 62            {
 163                var searchTerm = q.ToLower();
 164                query = query.Where(u =>
 165                    u.Username.ToLower().Contains(searchTerm) ||
 166                    (u.Persona != null && (
 167                        u.Persona.PrimerNombre.ToLower().Contains(searchTerm) ||
 168                        u.Persona.PrimerApellido.ToLower().Contains(searchTerm) ||
 169                        (u.Persona.SegundoNombre != null && u.Persona.SegundoNombre.ToLower().Contains(searchTerm)) ||
 170                        (u.Persona.SegundoApellido != null && u.Persona.SegundoApellido.ToLower().Contains(searchTerm)) 
 171                        (u.Persona.Email != null && u.Persona.Email.ToLower().Contains(searchTerm))
 172                    ))
 173                );
 74            }
 75
 576            var total = query.Count();
 77
 78            // Paginación
 579            var usuariosPaginados = query
 580                .Skip((page - 1) * pageSize)
 581                .Take(pageSize)
 582                .ToList()
 1483                .Select(u => new
 1484                {
 1485                    id = u.Id,
 1486                    usuario = u.Username,
 1487                    nombre = u.Persona != null ? u.Persona.NombreCompleto : "",
 1488                    email = u.Persona?.Email ?? "",
 1489                    rol = u.Roles.FirstOrDefault()?.Nombre ?? "",
 1490                    estado = u.Estado,
 1491                    ultimoAcceso = u.FechaActualizacion
 1492                })
 593                .ToList();
 94
 595            var response = new
 596            {
 597                items = usuariosPaginados,
 598                total = total,
 599                page = page,
 5100                pageSize = pageSize,
 5101                totalPages = (int)Math.Ceiling((double)total / pageSize)
 5102            };
 103
 5104            return Ok(ApiResponse<object>.SuccessResult(response));
 105        }
 1106        catch (Exception ex)
 107        {
 1108            _logger.LogError(ex, "Error al obtener usuarios");
 1109            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 110        }
 6111    }
 112
 113    /// <summary>
 114    /// Obtener detalle de usuario por ID
 115    /// GET /api/usuarios/{id}
 116    /// </summary>
 117    [HttpGet("{id}")]
 118    public async Task<IActionResult> GetUsuario(long id)
 119    {
 120        try
 121        {
 3122            var usuario = await _usuarioService.GetByIdAsync(id);
 123
 2124            if (usuario == null)
 125            {
 1126                return NotFound(ApiResponse<string>.ErrorResult("Usuario no encontrado"));
 127            }
 128
 1129            var response = new
 1130            {
 1131                id = usuario.Id,
 1132                usuario = usuario.Username,
 1133                nombre = usuario.Persona != null ? usuario.Persona.NombreCompleto : "",
 1134                email = usuario.Persona?.Email ?? "",
 1135                rolId = usuario.Roles.FirstOrDefault()?.Id,
 1136                estado = usuario.Estado
 1137            };
 138
 1139            return Ok(ApiResponse<object>.SuccessResult(response));
 140        }
 1141        catch (Exception ex)
 142        {
 1143            _logger.LogError(ex, "Error al obtener usuario {Id}", id);
 1144            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 145        }
 3146    }
 147
 148    /// <summary>
 149    /// Crear usuario con contraseña temporal
 150    /// POST /api/usuarios
 151    /// </summary>
 152    [HttpPost]
 153    public async Task<IActionResult> CreateUsuario([FromBody] CreateUsuarioRequest request)
 154    {
 155        try
 156        {
 157            // Validaciones
 3158            if (string.IsNullOrWhiteSpace(request.Username))
 159            {
 1160                return BadRequest(ApiResponse<string>.ErrorResult("El nombre de usuario es requerido"));
 161            }
 162
 2163            if (string.IsNullOrWhiteSpace(request.Password))
 164            {
 0165                return BadRequest(ApiResponse<string>.ErrorResult("La contraseña es requerida"));
 166            }
 167
 2168            var (success, usuario, error) = await _usuarioService.CreateAsync(
 2169                request.Username,
 2170                request.Password,
 2171                request.PersonaId);
 172
 2173            if (!success)
 174            {
 1175                if (error?.Contains("ya existe") == true || error?.Contains("ya está en uso") == true)
 176                {
 1177                    return Conflict(ApiResponse<string>.ErrorResult(error));
 178                }
 0179                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error al crear usuario"));
 180            }
 181
 182            // Asignar roles si se especificaron
 1183            if (request.RolesIds != null && request.RolesIds.Any())
 184            {
 4185                foreach (var rolId in request.RolesIds)
 186                {
 1187                    await _usuarioService.AsignarRolAsync(usuario!.Id, rolId);
 188                }
 189            }
 190
 1191            var response = new
 1192            {
 1193                id = usuario!.Id,
 1194                creado = true
 1195            };
 196
 1197            return CreatedAtAction(
 1198                nameof(GetUsuario),
 1199                new { id = usuario.Id },
 1200                ApiResponse<object>.SuccessResult(response, "Usuario creado exitosamente"));
 201        }
 0202        catch (Exception ex)
 203        {
 0204            _logger.LogError(ex, "Error al crear usuario");
 0205            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 206        }
 3207    }
 208
 209    /// <summary>
 210    /// Editar usuario (incluye activar/bloquear mediante campo estado)
 211    /// PUT /api/usuarios/{id}
 212    /// </summary>
 213    [HttpPut("{id}")]
 214    public async Task<IActionResult> UpdateUsuario(long id, [FromBody] UpdateUsuarioRequest request)
 215    {
 216        try
 217        {
 4218            var usuario = await _usuarioService.GetByIdAsync(id);
 3219            if (usuario == null)
 220            {
 1221                return NotFound(ApiResponse<string>.ErrorResult("Usuario no encontrado"));
 222            }
 223
 224            // Actualizar datos de persona si se proporcionan
 2225            if (usuario.Persona != null)
 226            {
 2227                if (!string.IsNullOrWhiteSpace(request.Nombre))
 228                {
 229                    // Asumiendo que nombre viene como "Nombre Apellido"
 1230                    var nombres = request.Nombre.Split(' ', 2);
 1231                    usuario.Persona.PrimerNombre = nombres[0];
 1232                    if (nombres.Length > 1)
 233                    {
 1234                        usuario.Persona.PrimerApellido = nombres[1];
 235                    }
 236                }
 237
 2238                if (!string.IsNullOrWhiteSpace(request.Email))
 239                {
 1240                    usuario.Persona.Email = request.Email;
 241                }
 242            }
 243
 244            // Cambiar rol si se especifica
 2245            if (request.RolId.HasValue)
 246            {
 247                // Remover roles actuales
 0248                var rolesActuales = usuario.Roles.ToList();
 0249                foreach (var rol in rolesActuales)
 250                {
 0251                    await _usuarioService.RemoverRolAsync(id, rol.Id);
 252                }
 253
 254                // Asignar nuevo rol
 0255                var (successRol, errorRol) = await _usuarioService.AsignarRolAsync(id, request.RolId.Value);
 0256                if (!successRol)
 257                {
 0258                    return BadRequest(ApiResponse<string>.ErrorResult(errorRol ?? "Error al asignar rol"));
 259                }
 260            }
 261
 262            // Cambiar estado si se especifica
 2263            if (!string.IsNullOrWhiteSpace(request.Estado))
 264            {
 2265                var (successEstado, errorEstado) = await _usuarioService.CambiarEstadoAsync(id, request.Estado);
 2266                if (!successEstado)
 267                {
 1268                    return BadRequest(ApiResponse<string>.ErrorResult(errorEstado ?? "Error al cambiar estado"));
 269                }
 270            }
 271
 1272            var response = new
 1273            {
 1274                actualizado = true
 1275            };
 276
 1277            return Ok(ApiResponse<object>.SuccessResult(response, "Usuario actualizado exitosamente"));
 278        }
 1279        catch (Exception ex)
 280        {
 1281            _logger.LogError(ex, "Error al actualizar usuario {Id}", id);
 1282            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 283        }
 4284    }
 285
 286    /// <summary>
 287    /// Cambiar contraseña de usuario (también para reset)
 288    /// PATCH /api/usuarios/{id}/password
 289    /// </summary>
 290    [HttpPatch("{id}/password")]
 291    public async Task<IActionResult> CambiarPassword(long id, [FromBody] CambiarPasswordRequest request)
 292    {
 293        try
 294        {
 4295            if (string.IsNullOrWhiteSpace(request.NuevaPassword))
 296            {
 1297                return BadRequest(ApiResponse<string>.ErrorResult("La nueva contraseña es requerida"));
 298            }
 299
 3300            var (success, error) = await _usuarioService.CambiarPasswordAsync(id, request.NuevaPassword);
 301
 2302            if (!success)
 303            {
 1304                if (error?.Contains("no encontrado") == true)
 305                {
 1306                    return NotFound(ApiResponse<string>.ErrorResult(error));
 307                }
 0308                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error al cambiar contraseña"));
 309            }
 310
 1311            var response = new
 1312            {
 1313                actualizado = true
 1314            };
 315
 1316            return Ok(ApiResponse<object>.SuccessResult(response, "Contraseña actualizada exitosamente"));
 317        }
 1318        catch (Exception ex)
 319        {
 1320            _logger.LogError(ex, "Error al cambiar contraseña del usuario {Id}", id);
 1321            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 322        }
 4323    }
 324}
 325