| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  | // src/Elecciones.Api/Controllers/AdminController.cs | 
					
						
							|  |  |  | using Elecciones.Database; | 
					
						
							|  |  |  | using Microsoft.AspNetCore.Mvc; | 
					
						
							|  |  |  | using Microsoft.EntityFrameworkCore; | 
					
						
							|  |  |  | using Elecciones.Core.DTOs.ApiRequests; | 
					
						
							|  |  |  | using Elecciones.Database.Entities; | 
					
						
							|  |  |  | using Microsoft.AspNetCore.Authorization; | 
					
						
							|  |  |  | using Elecciones.Core.Enums; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Elecciones.Api.Controllers; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [ApiController] | 
					
						
							|  |  |  | [Route("api/[controller]")]
 | 
					
						
							|  |  |  | [Authorize] | 
					
						
							|  |  |  | public class AdminController : ControllerBase | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   private readonly EleccionesDbContext _dbContext; | 
					
						
							|  |  |  |   private readonly ILogger<AdminController> _logger; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public AdminController(EleccionesDbContext dbContext, ILogger<AdminController> logger) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     _dbContext = dbContext; | 
					
						
							|  |  |  |     _logger = logger; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Endpoint para obtener todas las agrupaciones para el panel de admin | 
					
						
							|  |  |  |   [HttpGet("agrupaciones")] | 
					
						
							|  |  |  |   public async Task<IActionResult> GetAgrupaciones() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     var agrupaciones = await _dbContext.AgrupacionesPoliticas | 
					
						
							|  |  |  |         .AsNoTracking() | 
					
						
							|  |  |  |         .OrderBy(a => a.Nombre) | 
					
						
							|  |  |  |         .ToListAsync(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Ok(agrupaciones); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   [HttpPut("agrupaciones/{id}")] | 
					
						
							|  |  |  |   public async Task<IActionResult> UpdateAgrupacion(string id, [FromBody] UpdateAgrupacionDto agrupacionDto) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Buscamos la agrupación en la base de datos por su ID. | 
					
						
							|  |  |  |     var agrupacion = await _dbContext.AgrupacionesPoliticas.FindAsync(id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (agrupacion == null) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // Si no existe, devolvemos un error 404 Not Found. | 
					
						
							|  |  |  |       return NotFound(new { message = $"No se encontró la agrupación con ID {id}" }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Actualizamos las propiedades de la entidad con los valores del DTO. | 
					
						
							|  |  |  |     agrupacion.NombreCorto = agrupacionDto.NombreCorto; | 
					
						
							|  |  |  |     agrupacion.Color = agrupacionDto.Color; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Guardamos los cambios en la base de datos. | 
					
						
							|  |  |  |     await _dbContext.SaveChangesAsync(); | 
					
						
							|  |  |  |     _logger.LogInformation("Se actualizó la agrupación: {Id}", id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Devolvemos una respuesta 204 No Content, que es el estándar para un PUT exitoso sin devolver datos. | 
					
						
							|  |  |  |     return NoContent(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   [HttpPut("agrupaciones/orden-diputados")] | 
					
						
							|  |  |  |   public async Task<IActionResult> UpdateDiputadosOrden([FromBody] List<string> idsAgrupacionesOrdenadas) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Reseteamos solo el orden de diputados | 
					
						
							|  |  |  |     await _dbContext.AgrupacionesPoliticas.ExecuteUpdateAsync(s => s.SetProperty(a => a.OrdenDiputados, (int?)null)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = 0; i < idsAgrupacionesOrdenadas.Count; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       var agrupacion = await _dbContext.AgrupacionesPoliticas.FindAsync(idsAgrupacionesOrdenadas[i]); | 
					
						
							|  |  |  |       if (agrupacion != null) agrupacion.OrdenDiputados = i + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     await _dbContext.SaveChangesAsync(); | 
					
						
							|  |  |  |     return Ok(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   [HttpPut("agrupaciones/orden-senadores")] | 
					
						
							|  |  |  |   public async Task<IActionResult> UpdateSenadoresOrden([FromBody] List<string> idsAgrupacionesOrdenadas) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Reseteamos solo el orden de senadores | 
					
						
							|  |  |  |     await _dbContext.AgrupacionesPoliticas.ExecuteUpdateAsync(s => s.SetProperty(a => a.OrdenSenadores, (int?)null)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = 0; i < idsAgrupacionesOrdenadas.Count; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       var agrupacion = await _dbContext.AgrupacionesPoliticas.FindAsync(idsAgrupacionesOrdenadas[i]); | 
					
						
							|  |  |  |       if (agrupacion != null) agrupacion.OrdenSenadores = i + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     await _dbContext.SaveChangesAsync(); | 
					
						
							|  |  |  |     return Ok(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // LEER todas las configuraciones | 
					
						
							|  |  |  |   [HttpGet("configuracion")] | 
					
						
							|  |  |  |   public async Task<IActionResult> GetConfiguracion() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     var configs = await _dbContext.Configuraciones.AsNoTracking().ToListAsync(); | 
					
						
							|  |  |  |     // Devolvemos un diccionario para que sea fácil de consumir en el frontend | 
					
						
							|  |  |  |     return Ok(configs.ToDictionary(c => c.Clave, c => c.Valor)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // GUARDAR un conjunto de configuraciones | 
					
						
							|  |  |  |   [HttpPut("configuracion")] | 
					
						
							|  |  |  |   public async Task<IActionResult> UpdateConfiguracion([FromBody] Dictionary<string, string> nuevasConfiguraciones) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     foreach (var kvp in nuevasConfiguraciones) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       var config = await _dbContext.Configuraciones.FindAsync(kvp.Key); | 
					
						
							|  |  |  |       if (config == null) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // Si no existe, la creamos | 
					
						
							|  |  |  |         _dbContext.Configuraciones.Add(new Configuracion { Clave = kvp.Key, Valor = kvp.Value }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // Si existe, la actualizamos | 
					
						
							|  |  |  |         config.Valor = kvp.Value; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     await _dbContext.SaveChangesAsync(); | 
					
						
							|  |  |  |     return NoContent(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // LEER: Obtener todas las bancadas para una cámara, con su partido y ocupante actual | 
					
						
							|  |  |  |   [HttpGet("bancadas/{camara}")] | 
					
						
							|  |  |  |   public async Task<IActionResult> GetBancadas(TipoCamara camara) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     var bancadas = await _dbContext.Bancadas | 
					
						
							|  |  |  |         .AsNoTracking() | 
					
						
							|  |  |  |         .Include(b => b.AgrupacionPolitica) | 
					
						
							|  |  |  |         .Include(b => b.Ocupante) | 
					
						
							|  |  |  |         .Where(b => b.Camara == camara) | 
					
						
							|  |  |  |         .OrderBy(b => b.Id) // Ordenar por ID para consistencia | 
					
						
							|  |  |  |         .ToListAsync(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Ok(bancadas); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // ACTUALIZAR: Asignar un partido y/o un ocupante a una bancada específica | 
					
						
							|  |  |  |   [HttpPut("bancadas/{bancadaId}")] | 
					
						
							|  |  |  |   public async Task<IActionResult> UpdateBancada(int bancadaId, [FromBody] UpdateBancadaDto dto) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     var bancada = await _dbContext.Bancadas | 
					
						
							|  |  |  |         .Include(b => b.Ocupante) | 
					
						
							|  |  |  |         .FirstOrDefaultAsync(b => b.Id == bancadaId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (bancada == null) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return NotFound(new { message = "La bancada especificada no existe." }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 1. Actualizar la agrupación de la bancada | 
					
						
							|  |  |  |     bancada.AgrupacionPoliticaId = dto.AgrupacionPoliticaId; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 2. Lógica de "Upsert" (Update/Insert/Delete) para el ocupante | 
					
						
							|  |  |  |     if (string.IsNullOrEmpty(dto.NombreOcupante)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // Si no se envía nombre, se elimina el ocupante existente | 
					
						
							|  |  |  |       if (bancada.Ocupante != null) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         _dbContext.OcupantesBancas.Remove(bancada.Ocupante); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // Si se envía un nombre, se crea o actualiza el ocupante | 
					
						
							|  |  |  |       if (bancada.Ocupante == null) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         bancada.Ocupante = new OcupanteBanca(); // Crea uno nuevo si no existía | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       bancada.Ocupante.NombreOcupante = dto.NombreOcupante; | 
					
						
							|  |  |  |       bancada.Ocupante.FotoUrl = dto.FotoUrl; | 
					
						
							|  |  |  |       bancada.Ocupante.Periodo = dto.Periodo; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     await _dbContext.SaveChangesAsync(); | 
					
						
							|  |  |  |     _logger.LogInformation("Se actualizó la bancada con ID: {BancadaId}", bancadaId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return NoContent(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-01 14:04:40 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  |   [HttpGet("logos")] | 
					
						
							|  |  |  |   public async Task<IActionResult> GetLogos() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return Ok(await _dbContext.LogosAgrupacionesCategorias.AsNoTracking().ToListAsync()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   [HttpPut("logos")] | 
					
						
							|  |  |  |   public async Task<IActionResult> UpdateLogos([FromBody] List<LogoAgrupacionCategoria> logos) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Lógica de "Upsert" | 
					
						
							|  |  |  |     foreach (var logo in logos) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       var logoExistente = await _dbContext.LogosAgrupacionesCategorias | 
					
						
							|  |  |  |           .FirstOrDefaultAsync(l => l.AgrupacionPoliticaId == logo.AgrupacionPoliticaId && l.CategoriaId == logo.CategoriaId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (logoExistente != null) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         logoExistente.LogoUrl = logo.LogoUrl; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else if (!string.IsNullOrEmpty(logo.LogoUrl)) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         _dbContext.LogosAgrupacionesCategorias.Add(logo); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     await _dbContext.SaveChangesAsync(); | 
					
						
							|  |  |  |     return NoContent(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-08-29 09:54:22 -03:00
										 |  |  | } |