Trabajo de ajuste en widgets y db para frontend
This commit is contained in:
		
							
								
								
									
										181
									
								
								Elecciones-Web/src/Elecciones.Api/Controllers/AdminController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								Elecciones-Web/src/Elecciones.Api/Controllers/AdminController.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | ||||
| // 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; | ||||
|     agrupacion.LogoUrl = agrupacionDto.LogoUrl; | ||||
|  | ||||
|     // 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(); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,64 @@ | ||||
| using Elecciones.Core.Services; | ||||
| using Elecciones.Database; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Microsoft.IdentityModel.Tokens; | ||||
| using System.IdentityModel.Tokens.Jwt; | ||||
| using System.Security.Claims; | ||||
| using System.Text; | ||||
|  | ||||
| namespace Elecciones.Api.Controllers; | ||||
|  | ||||
| [ApiController] | ||||
| [Route("api/[controller]")] | ||||
| public class AuthController : ControllerBase | ||||
| { | ||||
|     private readonly EleccionesDbContext _context; | ||||
|     private readonly IPasswordHasher _passwordHasher; | ||||
|     private readonly IConfiguration _configuration; | ||||
|  | ||||
|     public AuthController(EleccionesDbContext context, IPasswordHasher passwordHasher, IConfiguration configuration) | ||||
|     { | ||||
|         _context = context; | ||||
|         _passwordHasher = passwordHasher; | ||||
|         _configuration = configuration; | ||||
|     } | ||||
|  | ||||
|     public record LoginRequest(string Username, string Password); | ||||
|  | ||||
|     [HttpPost("login")] | ||||
|     public async Task<IActionResult> Login([FromBody] LoginRequest loginRequest) | ||||
|     { | ||||
|         var user = await _context.AdminUsers | ||||
|             .FirstOrDefaultAsync(u => u.Username == loginRequest.Username); | ||||
|  | ||||
|         if (user == null || !_passwordHasher.VerifyPassword(loginRequest.Password, user.PasswordHash, user.PasswordSalt)) | ||||
|         { | ||||
|             return Unauthorized(new { message = "Credenciales inválidas." }); | ||||
|         } | ||||
|  | ||||
|         var token = GenerateJwtToken(user); | ||||
|         return Ok(new { token }); | ||||
|     } | ||||
|  | ||||
|     private string GenerateJwtToken(Database.Entities.AdminUser user) | ||||
|     { | ||||
|         var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]!)); | ||||
|         var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); | ||||
|  | ||||
|         var claims = new[] | ||||
|         { | ||||
|             new Claim(JwtRegisteredClaimNames.Sub, user.Username), | ||||
|             new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) | ||||
|         }; | ||||
|  | ||||
|         var token = new JwtSecurityToken( | ||||
|             issuer: _configuration["Jwt:Issuer"], | ||||
|             audience: _configuration["Jwt:Audience"], | ||||
|             claims: claims, | ||||
|             expires: DateTime.UtcNow.AddHours(8), // El token expira en 8 horas | ||||
|             signingCredentials: credentials); | ||||
|  | ||||
|         return new JwtSecurityTokenHandler().WriteToken(token); | ||||
|     } | ||||
| } | ||||
| @@ -2,8 +2,6 @@ using Elecciones.Core.DTOs.ApiResponses; | ||||
| using Elecciones.Database; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Elecciones.Api.Controllers; | ||||
|  | ||||
|   | ||||
| @@ -1,13 +1,9 @@ | ||||
| // src/Elecciones.Api/Controllers/ResultadosController.cs | ||||
| using Elecciones.Core.DTOs.ApiResponses; | ||||
| using Elecciones.Database; | ||||
| using Elecciones.Database.Entities; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Elecciones.Core.DTOs.Configuration; | ||||
|  | ||||
| namespace Elecciones.Api.Controllers; | ||||
|  | ||||
| @@ -208,28 +204,23 @@ public class ResultadosController : ControllerBase | ||||
|             }); | ||||
|  | ||||
|         var resultadosGanadores = await _dbContext.ResultadosVotos | ||||
|             .Join( | ||||
|                 maxVotosPorAmbito, | ||||
|                 voto => new { AmbitoId = voto.AmbitoGeograficoId, Votos = voto.CantidadVotos }, | ||||
|                 max => new { AmbitoId = max.AmbitoId, Votos = max.MaxVotos }, | ||||
|                 (voto, max) => voto | ||||
|             ) | ||||
|             .Include(rv => rv.AmbitoGeografico) | ||||
|             .Where(rv => rv.AmbitoGeografico.NivelId == 30) // Aseguramos que solo sean los ámbitos de nivel 30 | ||||
|             .Select(rv => new | ||||
|             { | ||||
|                 // CORRECCIÓN CLAVE: Devolvemos los campos que el frontend necesita para funcionar. | ||||
|  | ||||
|                 // 1. El ID de la BD para hacer clic y pedir detalles. | ||||
|                 AmbitoId = rv.AmbitoGeografico.Id, | ||||
|  | ||||
|                 // 2. El NOMBRE del departamento/municipio para encontrar y colorear el polígono. | ||||
|                 DepartamentoNombre = rv.AmbitoGeografico.Nombre, | ||||
|  | ||||
|                 // 3. El ID del partido ganador. | ||||
|                 AgrupacionGanadoraId = rv.AgrupacionPoliticaId | ||||
|             }) | ||||
|             .ToListAsync(); | ||||
|     .Join( | ||||
|         maxVotosPorAmbito, | ||||
|         voto => new { AmbitoId = voto.AmbitoGeograficoId, Votos = voto.CantidadVotos }, | ||||
|         max => new { AmbitoId = max.AmbitoId, Votos = max.MaxVotos }, | ||||
|         (voto, max) => voto | ||||
|     ) | ||||
|     .Include(rv => rv.AmbitoGeografico) | ||||
|     .Include(rv => rv.AgrupacionPolitica) | ||||
|     .Where(rv => rv.AmbitoGeografico.NivelId == 30) | ||||
|     .Select(rv => new | ||||
|     { | ||||
|         AmbitoId = rv.AmbitoGeografico.Id, | ||||
|         DepartamentoNombre = rv.AmbitoGeografico.Nombre, | ||||
|         AgrupacionGanadoraId = rv.AgrupacionPoliticaId, | ||||
|         ColorGanador = rv.AgrupacionPolitica.Color | ||||
|     }) | ||||
|     .ToListAsync(); | ||||
|  | ||||
|         return Ok(resultadosGanadores); | ||||
|     } | ||||
| @@ -298,18 +289,239 @@ public class ResultadosController : ControllerBase | ||||
|     } | ||||
|  | ||||
|     [HttpGet("composicion-congreso")] | ||||
|     public IActionResult GetComposicionCongreso() | ||||
|     public async Task<IActionResult> GetComposicionCongreso() | ||||
|     { | ||||
|         // El framework .NET se encarga de leer appsettings.json y mapearlo a nuestras clases. | ||||
|         var composicionConfig = _configuration.GetSection("ComposicionCongreso") | ||||
|                                               .Get<ComposicionCongresoConfig>(); | ||||
|         var config = await _dbContext.Configuraciones | ||||
|             .AsNoTracking() | ||||
|             .ToDictionaryAsync(c => c.Clave, c => c.Valor); | ||||
|  | ||||
|         if (composicionConfig == null) | ||||
|         config.TryGetValue("UsarDatosDeBancadasOficiales", out var usarDatosOficialesValue); | ||||
|         bool usarDatosOficiales = usarDatosOficialesValue == "true"; | ||||
|  | ||||
|         if (usarDatosOficiales) | ||||
|         { | ||||
|             // Devolvemos un error si la sección no se encuentra en el archivo de configuración. | ||||
|             return NotFound("La configuración para la composición del congreso no fue encontrada."); | ||||
|             return await GetComposicionDesdeBancadasOficiales(config); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return await GetComposicionDesdeProyecciones(config); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task<IActionResult> GetComposicionDesdeBancadasOficiales(Dictionary<string, string> config) | ||||
|     { | ||||
|         config.TryGetValue("MostrarOcupantes", out var mostrarOcupantesValue); | ||||
|         bool mostrarOcupantes = mostrarOcupantesValue == "true"; | ||||
|  | ||||
|         // Se declara la variable explícitamente como IQueryable<Bancada> | ||||
|         IQueryable<Bancada> bancadasQuery = _dbContext.Bancadas.AsNoTracking() | ||||
|                                                      .Include(b => b.AgrupacionPolitica); | ||||
|  | ||||
|         if (mostrarOcupantes) | ||||
|         { | ||||
|             // Ahora sí podemos añadir otro .Include() sin problemas de tipo | ||||
|             bancadasQuery = bancadasQuery.Include(b => b.Ocupante); | ||||
|         } | ||||
|  | ||||
|         return Ok(composicionConfig); | ||||
|         var bancadas = await bancadasQuery.ToListAsync(); | ||||
|  | ||||
|         // --- CAMBIO 2: Eliminar la carga manual de Ocupantes --- | ||||
|         // Ya no necesitamos 'ocupantesLookup'. Se puede borrar todo este bloque: | ||||
|         /* | ||||
|         var ocupantesLookup = new Dictionary<int, OcupanteBanca>(); | ||||
|         if (mostrarOcupantes) | ||||
|         { | ||||
|             ocupantesLookup = (await _dbContext.OcupantesBancas.AsNoTracking() | ||||
|                 .ToListAsync()) | ||||
|                 .ToDictionary(o => o.BancadaId); | ||||
|         } | ||||
|         */ | ||||
|  | ||||
|         var bancasPorAgrupacion = bancadas | ||||
|             .Where(b => b.AgrupacionPoliticaId != null) | ||||
|             .GroupBy(b => new { b.AgrupacionPoliticaId, b.Camara }) | ||||
|             .Select(g => new | ||||
|             { | ||||
|                 Agrupacion = g.First().AgrupacionPolitica, | ||||
|                 g.Key.Camara, | ||||
|                 BancasTotales = g.Count() | ||||
|             }) | ||||
|             .ToList(); | ||||
|  | ||||
|         var presidenteDiputados = bancasPorAgrupacion | ||||
|             .Where(b => b.Camara == Core.Enums.TipoCamara.Diputados) | ||||
|             .OrderByDescending(b => b.BancasTotales) | ||||
|             .FirstOrDefault()?.Agrupacion; | ||||
|  | ||||
|         config.TryGetValue("PresidenciaSenadores", out var idPartidoPresidenteSenadores); | ||||
|         var presidenteSenadores = await _dbContext.AgrupacionesPoliticas.FindAsync(idPartidoPresidenteSenadores); | ||||
|  | ||||
|         object MapearPartidos(Core.Enums.TipoCamara camara) | ||||
|         { | ||||
|             // 1. Filtramos las bancadas que nos interesan (por cámara y que tengan partido). | ||||
|             var bancadasDeCamara = bancadas | ||||
|                 .Where(b => b.Camara == camara && b.AgrupacionPolitica != null); | ||||
|  | ||||
|             // 2. --- ¡EL CAMBIO CLAVE ESTÁ AQUÍ! --- | ||||
|             // Agrupamos por el ID de la Agrupación, no por el objeto. | ||||
|             // Esto garantiza que todas las bancadas del mismo partido terminen en el MISMO grupo. | ||||
|             var partidosDeCamara = bancadasDeCamara | ||||
|                 .GroupBy(b => b.AgrupacionPolitica!.Id) | ||||
|                 .Select(g => new | ||||
|                 { | ||||
|                     // La Agrupacion la podemos tomar del primer elemento del grupo, | ||||
|                     // ya que todas las bancadas del grupo pertenecen al mismo partido. | ||||
|                     Agrupacion = g.First().AgrupacionPolitica!, | ||||
|                     // g ahora contiene la lista COMPLETA de bancadas para esta agrupación. | ||||
|                     BancasDelPartido = g.ToList() | ||||
|                 }); | ||||
|  | ||||
|             // 3. Ordenamos, como antes, pero ahora sobre una lista de grupos correcta. | ||||
|             var partidosOrdenados = (camara == Core.Enums.TipoCamara.Diputados) | ||||
|                 ? partidosDeCamara.OrderBy(p => p.Agrupacion.OrdenDiputados ?? 999) | ||||
|                 : partidosDeCamara.OrderBy(p => p.Agrupacion.OrdenSenadores ?? 999); | ||||
|  | ||||
|             // 4. Mapeamos al resultado final. | ||||
|             return partidosOrdenados | ||||
|                 .ThenByDescending(p => p.BancasDelPartido.Count) | ||||
|                 .Select(p => | ||||
|                 { | ||||
|                     // Ahora 'p.BancasDelPartido' contiene TODAS las bancadas del partido (en tu caso, las 2). | ||||
|                     // Cuando hagamos el .Select() aquí, recorrerá ambas y encontrará a los ocupantes. | ||||
|                     var ocupantesDelPartido = p.BancasDelPartido | ||||
|                         .Select(b => b.Ocupante) | ||||
|                         .Where(o => o != null) | ||||
|                         .ToList(); | ||||
|  | ||||
|                     return new | ||||
|                     { | ||||
|                         p.Agrupacion.Id, | ||||
|                         p.Agrupacion.Nombre, | ||||
|                         p.Agrupacion.NombreCorto, | ||||
|                         p.Agrupacion.Color, | ||||
|                         BancasTotales = p.BancasDelPartido.Count, | ||||
|                         // ¡Esta lista ahora debería contener a tus 2 ocupantes! | ||||
|                         Ocupantes = mostrarOcupantes ? ocupantesDelPartido : new List<OcupanteBanca?>() | ||||
|                     }; | ||||
|                 }).ToList(); | ||||
|         } | ||||
|  | ||||
|         // El resto del método permanece igual... | ||||
|         var diputados = new | ||||
|         { | ||||
|             CamaraNombre = "Cámara de Diputados", | ||||
|             TotalBancas = 92, | ||||
|             BancasEnJuego = 0, | ||||
|             Partidos = MapearPartidos(Core.Enums.TipoCamara.Diputados), | ||||
|             PresidenteBancada = presidenteDiputados != null ? new { presidenteDiputados.Color } : null | ||||
|         }; | ||||
|  | ||||
|         var senadores = new | ||||
|         { | ||||
|             CamaraNombre = "Cámara de Senadores", | ||||
|             TotalBancas = 46, | ||||
|             BancasEnJuego = 0, | ||||
|             Partidos = MapearPartidos(Core.Enums.TipoCamara.Senadores), | ||||
|             PresidenteBancada = presidenteSenadores != null ? new { presidenteSenadores.Color } : null | ||||
|         }; | ||||
|  | ||||
|         return Ok(new { Diputados = diputados, Senadores = senadores }); | ||||
|     } | ||||
|  | ||||
|     private async Task<IActionResult> GetComposicionDesdeProyecciones(Dictionary<string, string> config) | ||||
|     { | ||||
|         var bancasPorAgrupacion = await _dbContext.ProyeccionesBancas | ||||
|             .AsNoTracking() | ||||
|             .GroupBy(p => new { p.AgrupacionPoliticaId, p.CategoriaId }) | ||||
|             .Select(g => new | ||||
|             { | ||||
|                 AgrupacionId = g.Key.AgrupacionPoliticaId, | ||||
|                 CategoriaId = g.Key.CategoriaId, | ||||
|                 BancasTotales = g.Sum(p => p.NroBancas) | ||||
|             }) | ||||
|             .ToListAsync(); | ||||
|  | ||||
|         var todasAgrupaciones = await _dbContext.AgrupacionesPoliticas.AsNoTracking().ToDictionaryAsync(a => a.Id); | ||||
|  | ||||
|         config.TryGetValue("PresidenciaSenadores", out var idPartidoPresidenteSenadores); | ||||
|         todasAgrupaciones.TryGetValue(idPartidoPresidenteSenadores ?? "", out var presidenteSenadores); | ||||
|  | ||||
|         string? idPartidoPresidenteDiputados = bancasPorAgrupacion | ||||
|             .Where(b => b.CategoriaId == 6) | ||||
|             .OrderByDescending(b => b.BancasTotales) | ||||
|             .FirstOrDefault()?.AgrupacionId; | ||||
|         todasAgrupaciones.TryGetValue(idPartidoPresidenteDiputados ?? "", out var presidenteDiputados); | ||||
|  | ||||
|         object MapearPartidos(int categoriaId) | ||||
|         { | ||||
|             var partidosDeCamara = bancasPorAgrupacion | ||||
|                 .Where(b => b.CategoriaId == categoriaId && b.BancasTotales > 0) | ||||
|                 .Select(b => new { Bancas = b, Agrupacion = todasAgrupaciones[b.AgrupacionId] }); | ||||
|  | ||||
|             if (categoriaId == 6) // Diputados | ||||
|                 partidosDeCamara = partidosDeCamara.OrderBy(b => b.Agrupacion.OrdenDiputados ?? 999) | ||||
|                                                    .ThenByDescending(b => b.Bancas.BancasTotales); | ||||
|             else // Senadores | ||||
|                 partidosDeCamara = partidosDeCamara.OrderBy(b => b.Agrupacion.OrdenSenadores ?? 999) | ||||
|                                                    .ThenByDescending(b => b.Bancas.BancasTotales); | ||||
|  | ||||
|             return partidosDeCamara | ||||
|                 .Select(b => new | ||||
|                 { | ||||
|                     b.Agrupacion.Id, | ||||
|                     b.Agrupacion.Nombre, | ||||
|                     b.Agrupacion.NombreCorto, | ||||
|                     b.Agrupacion.Color, | ||||
|                     b.Bancas.BancasTotales | ||||
|                 }) | ||||
|                 .ToList(); | ||||
|         } | ||||
|  | ||||
|         var diputados = new | ||||
|         { | ||||
|             CamaraNombre = "Cámara de Diputados", | ||||
|             TotalBancas = 92, | ||||
|             BancasEnJuego = 46, | ||||
|             Partidos = MapearPartidos(6), | ||||
|             PresidenteBancada = presidenteDiputados != null ? new { presidenteDiputados.Color } : null | ||||
|         }; | ||||
|  | ||||
|         var senadores = new | ||||
|         { | ||||
|             CamaraNombre = "Cámara de Senadores", | ||||
|             TotalBancas = 46, | ||||
|             BancasEnJuego = 23, | ||||
|             Partidos = MapearPartidos(5), | ||||
|             PresidenteBancada = presidenteSenadores != null ? new { presidenteSenadores.Color } : null | ||||
|         }; | ||||
|  | ||||
|         return Ok(new { Diputados = diputados, Senadores = senadores }); | ||||
|     } | ||||
|  | ||||
|     [HttpGet("bancadas-detalle")] | ||||
|     public async Task<IActionResult> GetBancadasConOcupantes() | ||||
|     { | ||||
|         var config = await _dbContext.Configuraciones.AsNoTracking().ToDictionaryAsync(c => c.Clave, c => c.Valor); | ||||
|         config.TryGetValue("MostrarOcupantes", out var mostrarOcupantesValue); | ||||
|         if (mostrarOcupantesValue != "true") | ||||
|         { | ||||
|             // Si la opción está desactivada, devolvemos un array vacío. | ||||
|             return Ok(new List<object>()); | ||||
|         } | ||||
|  | ||||
|         var bancadasConOcupantes = await _dbContext.Bancadas | ||||
|             .AsNoTracking() | ||||
|             .Include(b => b.Ocupante) | ||||
|             .Where(b => b.Ocupante != null) // Solo las que tienen un ocupante asignado | ||||
|             .Select(b => new | ||||
|             { | ||||
|                 b.Id, | ||||
|                 b.Camara, | ||||
|                 b.AgrupacionPoliticaId, | ||||
|                 Ocupante = b.Ocupante | ||||
|             }) | ||||
|             .ToListAsync(); | ||||
|  | ||||
|         return Ok(bancadasConOcupantes); | ||||
|     } | ||||
| } | ||||
| @@ -1,9 +1,6 @@ | ||||
| using Elecciones.Core.DTOs.ApiResponses; | ||||
| using Elecciones.Database; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Elecciones.Api.Controllers; | ||||
|  | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.8" /> | ||||
|     <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.5" /> | ||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.8" /> | ||||
|     <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.8"> | ||||
|   | ||||
| @@ -1,6 +1,13 @@ | ||||
| using Elecciones.Database; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Serilog; | ||||
| using Elecciones.Core.Services; | ||||
| using Elecciones.Infrastructure.Services; | ||||
| using System.Text; | ||||
| using Microsoft.AspNetCore.Authentication.JwtBearer; | ||||
| using Microsoft.IdentityModel.Tokens; | ||||
| using Elecciones.Database.Entities; | ||||
| using System.Text.Json.Serialization; | ||||
|  | ||||
| // Esta es la estructura estándar y recomendada. | ||||
| var builder = WebApplication.CreateBuilder(args); | ||||
| @@ -18,22 +25,44 @@ var connectionString = builder.Configuration.GetConnectionString("DefaultConnect | ||||
| builder.Services.AddDbContext<EleccionesDbContext>(options => | ||||
|     options.UseSqlServer(connectionString)); | ||||
|  | ||||
| builder.Services.AddControllers(); | ||||
| builder.Services.AddScoped<IPasswordHasher, PasswordHasher>(); | ||||
|  | ||||
| var allowedOrigins = builder.Configuration["AllowedOrigins"]?.Split(',') ?? Array.Empty<string>(); | ||||
| builder.Services.AddControllers().AddJsonOptions(options => | ||||
| { | ||||
|     // Esto le dice al serializador que maneje las referencias circulares | ||||
|     options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; | ||||
| }); | ||||
|  | ||||
| var MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; | ||||
| builder.Services.AddCors(options => | ||||
| { | ||||
|     options.AddDefaultPolicy(policy => | ||||
|     { | ||||
|         if (allowedOrigins.Any()) | ||||
|         { | ||||
|             policy.WithOrigins(allowedOrigins) | ||||
|                   .AllowAnyHeader() | ||||
|                   .AllowAnyMethod(); | ||||
|         } | ||||
|     }); | ||||
|     options.AddPolicy(name: MyAllowSpecificOrigins, | ||||
|                       policy => | ||||
|                       { | ||||
|                           policy.WithOrigins( | ||||
|                               "http://localhost:5173", // Para widgets | ||||
|                               "http://localhost:5174"  // Para admin | ||||
|                           )  | ||||
|                           .AllowAnyHeader() | ||||
|                           .AllowAnyMethod(); | ||||
|                       }); | ||||
| }); | ||||
|  | ||||
| builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) | ||||
|     .AddJwtBearer(options => | ||||
|     { | ||||
|         options.TokenValidationParameters = new TokenValidationParameters | ||||
|         { | ||||
|             ValidateIssuer = true, | ||||
|             ValidateAudience = true, | ||||
|             ValidateLifetime = true, | ||||
|             ValidateIssuerSigningKey = true, | ||||
|             ValidIssuer = builder.Configuration["Jwt:Issuer"], | ||||
|             ValidAudience = builder.Configuration["Jwt:Audience"], | ||||
|             IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!)) | ||||
|         }; | ||||
|     }); | ||||
|  | ||||
| builder.Services.AddEndpointsApiExplorer(); | ||||
| builder.Services.AddSwaggerGen(); | ||||
|  | ||||
| @@ -41,7 +70,72 @@ builder.Services.AddSwaggerGen(); | ||||
| // 3. Construir la aplicación. | ||||
| var app = builder.Build(); | ||||
|  | ||||
| // 4. Configurar el pipeline de peticiones HTTP. | ||||
| // Seeder para el usuario admin | ||||
| using (var scope = app.Services.CreateScope()) | ||||
| { | ||||
|     var services = scope.ServiceProvider; | ||||
|     try | ||||
|     { | ||||
|         var context = services.GetRequiredService<EleccionesDbContext>(); | ||||
|         var hasher = services.GetRequiredService<IPasswordHasher>(); | ||||
|         if (!context.AdminUsers.Any()) | ||||
|         { | ||||
|             var (hash, salt) = hasher.HashPassword("PTP847elec"); | ||||
|             context.AdminUsers.Add(new Elecciones.Database.Entities.AdminUser | ||||
|             { | ||||
|                 Username = "admin", | ||||
|                 PasswordHash = hash, | ||||
|                 PasswordSalt = salt | ||||
|             }); | ||||
|             context.SaveChanges(); | ||||
|             Console.WriteLine("--> Admin user seeded."); | ||||
|         } | ||||
|     } | ||||
|     catch (Exception ex) | ||||
|     { | ||||
|         var logger = services.GetRequiredService<ILogger<Program>>(); | ||||
|         logger.LogError(ex, "An error occurred while seeding the database."); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Seeder para las bancas vacías | ||||
| using (var scope = app.Services.CreateScope()) | ||||
| { | ||||
|     var services = scope.ServiceProvider; | ||||
|     var context = services.GetRequiredService<EleccionesDbContext>(); | ||||
|     if (!context.Bancadas.Any()) | ||||
|     { | ||||
|         var bancas = new List<Bancada>(); | ||||
|         // 92 bancas de diputados | ||||
|         for (int i = 0; i < 92; i++) | ||||
|         { | ||||
|             bancas.Add(new Bancada { Camara = Elecciones.Core.Enums.TipoCamara.Diputados }); | ||||
|         } | ||||
|         // 46 bancas de senadores | ||||
|         for (int i = 0; i < 46; i++) | ||||
|         { | ||||
|             bancas.Add(new Bancada { Camara = Elecciones.Core.Enums.TipoCamara.Senadores }); | ||||
|         } | ||||
|         context.Bancadas.AddRange(bancas); | ||||
|         context.SaveChanges(); | ||||
|         Console.WriteLine("--> Seeded 138 empty bancas."); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Seeder para las configuraciones por defecto | ||||
| using (var scope = app.Services.CreateScope()) | ||||
| { | ||||
|     var services = scope.ServiceProvider; | ||||
|     var context = services.GetRequiredService<EleccionesDbContext>(); | ||||
|     if (!context.Configuraciones.Any(c => c.Clave == "MostrarOcupantes")) | ||||
|     { | ||||
|         context.Configuraciones.Add(new Configuracion { Clave = "MostrarOcupantes", Valor = "true" }); | ||||
|         context.SaveChanges(); | ||||
|         Console.WriteLine("--> Seeded default configuration 'MostrarOcupantes'."); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Configurar el pipeline de peticiones HTTP. | ||||
| // Añadimos el logging de peticiones de Serilog aquí. | ||||
| app.UseSerilogRequestLogging(); | ||||
|  | ||||
| @@ -51,11 +145,27 @@ if (app.Environment.IsDevelopment()) | ||||
|     app.UseSwaggerUI(); | ||||
| } | ||||
|  | ||||
| app.UseHttpsRedirection(); | ||||
| app.UseCors(); | ||||
| // 1. Redirección a HTTPS (si se usa) | ||||
| //app.UseHttpsRedirection(); | ||||
|  | ||||
| // 2. Middleware de Enrutamiento. ¡CLAVE! | ||||
| //    Determina a qué endpoint irá la petición. | ||||
| app.UseRouting(); | ||||
|  | ||||
| // 3. Middleware de CORS. | ||||
| //    Ahora se ejecuta sabiendo a qué endpoint se dirige la petición. | ||||
| app.UseCors(MyAllowSpecificOrigins); | ||||
|  | ||||
| // 4. Middleware de Autenticación. | ||||
| //    Identifica quién es el usuario a partir del token. | ||||
| app.UseAuthentication(); | ||||
|  | ||||
| // 5. Middleware de Autorización. | ||||
| //    Verifica si el usuario identificado tiene permiso para acceder al endpoint. | ||||
| app.UseAuthorization(); | ||||
|  | ||||
| // 6. Mapea los controladores a los endpoints que el enrutador descubrió. | ||||
| app.MapControllers(); | ||||
|  | ||||
| // 5. Ejecutar la aplicación. | ||||
| // El try/catch/finally se puede omitir; el logging de Serilog ya se encarga de los errores fatales. | ||||
| app.Run(); | ||||
| @@ -0,0 +1,24 @@ | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.AspNetCore.Mvc.Filters; | ||||
|  | ||||
| namespace Elecciones.Api.Security; | ||||
|  | ||||
| [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | ||||
| public class ApiKeyAuthAttribute : Attribute, IAsyncActionFilter | ||||
| { | ||||
|     private const string ApiKeyHeaderName = "X-Api-Key"; | ||||
|  | ||||
|     public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) | ||||
|     { | ||||
|         var configuration = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>(); | ||||
|         var apiKey = configuration.GetValue<string>("ApiKey"); | ||||
|  | ||||
|         if (!context.HttpContext.Request.Headers.TryGetValue(ApiKeyHeaderName, out var potentialApiKey) || apiKey == null || !apiKey.Equals(potentialApiKey)) | ||||
|         { | ||||
|             context.Result = new UnauthorizedResult(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         await next(); | ||||
|     } | ||||
| } | ||||
| @@ -8,7 +8,6 @@ | ||||
|       "Microsoft.AspNetCore": "Warning" | ||||
|     } | ||||
|   }, | ||||
|   "AllowedOrigins": "http://localhost:5173", | ||||
|  | ||||
|   "ComposicionCongreso": { | ||||
|     "Diputados": { | ||||
| @@ -34,5 +33,11 @@ | ||||
|         { "Id": "507_S", "Nombre": "CANDIDATURA 507", "BancasTotales": 5, "BancasEnJuego": 2, "Color": "#9467bd" } | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
|   "ApiKey": "badb1a38d221c9e23bcf70958840ca7f5a5dc54f2047dadf7ce45b578b5bc3e2", | ||||
|   "Jwt": { | ||||
|     "Key": "badb1a38d221c9e23bcf70958840ca7f5a5dc54f2047dadf7ce45b578b5bc3e2", | ||||
|     "Issuer": "EleccionesApi", | ||||
|     "Audience": "AdminPanel" | ||||
|   } | ||||
| } | ||||
| @@ -10,6 +10,7 @@ | ||||
|         "dependencies": { | ||||
|           "Elecciones.Database": "1.0.0", | ||||
|           "Elecciones.Infrastructure": "1.0.0", | ||||
|           "Microsoft.AspNetCore.Authentication.JwtBearer": "9.0.8", | ||||
|           "Microsoft.AspNetCore.OpenApi": "9.0.5", | ||||
|           "Microsoft.EntityFrameworkCore.SqlServer": "9.0.8", | ||||
|           "Microsoft.EntityFrameworkCore.Tools": "9.0.8", | ||||
| @@ -64,6 +65,17 @@ | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.AspNetCore.Authentication.JwtBearer/9.0.8": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.IdentityModel.Protocols.OpenIdConnect": "8.0.1" | ||||
|         }, | ||||
|         "runtime": { | ||||
|           "lib/net9.0/Microsoft.AspNetCore.Authentication.JwtBearer.dll": { | ||||
|             "assemblyVersion": "9.0.8.0", | ||||
|             "fileVersion": "9.0.825.36808" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.AspNetCore.OpenApi/9.0.5": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.OpenApi": "1.6.23" | ||||
| @@ -371,14 +383,13 @@ | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.CSharp/4.5.0": {}, | ||||
|       "Microsoft.Data.SqlClient/5.1.6": { | ||||
|         "dependencies": { | ||||
|           "Azure.Identity": "1.11.4", | ||||
|           "Microsoft.Data.SqlClient.SNI.runtime": "5.1.1", | ||||
|           "Microsoft.Identity.Client": "4.61.3", | ||||
|           "Microsoft.IdentityModel.JsonWebTokens": "6.35.0", | ||||
|           "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.35.0", | ||||
|           "Microsoft.IdentityModel.JsonWebTokens": "8.0.1", | ||||
|           "Microsoft.IdentityModel.Protocols.OpenIdConnect": "8.0.1", | ||||
|           "Microsoft.SqlServer.Server": "1.0.0", | ||||
|           "System.Configuration.ConfigurationManager": "6.0.1", | ||||
|           "System.Diagnostics.DiagnosticSource": "6.0.1", | ||||
| @@ -719,7 +730,7 @@ | ||||
|       }, | ||||
|       "Microsoft.Identity.Client/4.61.3": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.IdentityModel.Abstractions": "6.35.0", | ||||
|           "Microsoft.IdentityModel.Abstractions": "8.0.1", | ||||
|           "System.Diagnostics.DiagnosticSource": "6.0.1" | ||||
|         }, | ||||
|         "runtime": { | ||||
| @@ -741,78 +752,70 @@ | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.IdentityModel.Abstractions/6.35.0": { | ||||
|       "Microsoft.IdentityModel.Abstractions/8.0.1": { | ||||
|         "runtime": { | ||||
|           "lib/net6.0/Microsoft.IdentityModel.Abstractions.dll": { | ||||
|             "assemblyVersion": "6.35.0.0", | ||||
|             "fileVersion": "6.35.0.41201" | ||||
|           "lib/net9.0/Microsoft.IdentityModel.Abstractions.dll": { | ||||
|             "assemblyVersion": "8.0.1.0", | ||||
|             "fileVersion": "8.0.1.50722" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.IdentityModel.JsonWebTokens/6.35.0": { | ||||
|       "Microsoft.IdentityModel.JsonWebTokens/8.0.1": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.IdentityModel.Tokens": "6.35.0", | ||||
|           "System.Text.Encoding": "4.3.0", | ||||
|           "System.Text.Encodings.Web": "6.0.0", | ||||
|           "System.Text.Json": "9.0.8" | ||||
|           "Microsoft.IdentityModel.Tokens": "8.0.1" | ||||
|         }, | ||||
|         "runtime": { | ||||
|           "lib/net6.0/Microsoft.IdentityModel.JsonWebTokens.dll": { | ||||
|             "assemblyVersion": "6.35.0.0", | ||||
|             "fileVersion": "6.35.0.41201" | ||||
|           "lib/net9.0/Microsoft.IdentityModel.JsonWebTokens.dll": { | ||||
|             "assemblyVersion": "8.0.1.0", | ||||
|             "fileVersion": "8.0.1.50722" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.IdentityModel.Logging/6.35.0": { | ||||
|       "Microsoft.IdentityModel.Logging/8.0.1": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.IdentityModel.Abstractions": "6.35.0" | ||||
|           "Microsoft.IdentityModel.Abstractions": "8.0.1" | ||||
|         }, | ||||
|         "runtime": { | ||||
|           "lib/net6.0/Microsoft.IdentityModel.Logging.dll": { | ||||
|             "assemblyVersion": "6.35.0.0", | ||||
|             "fileVersion": "6.35.0.41201" | ||||
|           "lib/net9.0/Microsoft.IdentityModel.Logging.dll": { | ||||
|             "assemblyVersion": "8.0.1.0", | ||||
|             "fileVersion": "8.0.1.50722" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.IdentityModel.Protocols/6.35.0": { | ||||
|       "Microsoft.IdentityModel.Protocols/8.0.1": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.IdentityModel.Logging": "6.35.0", | ||||
|           "Microsoft.IdentityModel.Tokens": "6.35.0" | ||||
|           "Microsoft.IdentityModel.Tokens": "8.0.1" | ||||
|         }, | ||||
|         "runtime": { | ||||
|           "lib/net6.0/Microsoft.IdentityModel.Protocols.dll": { | ||||
|             "assemblyVersion": "6.35.0.0", | ||||
|             "fileVersion": "6.35.0.41201" | ||||
|           "lib/net9.0/Microsoft.IdentityModel.Protocols.dll": { | ||||
|             "assemblyVersion": "8.0.1.0", | ||||
|             "fileVersion": "8.0.1.50722" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.IdentityModel.Protocols.OpenIdConnect/6.35.0": { | ||||
|       "Microsoft.IdentityModel.Protocols.OpenIdConnect/8.0.1": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.IdentityModel.Protocols": "6.35.0", | ||||
|           "System.IdentityModel.Tokens.Jwt": "6.35.0" | ||||
|           "Microsoft.IdentityModel.Protocols": "8.0.1", | ||||
|           "System.IdentityModel.Tokens.Jwt": "8.0.1" | ||||
|         }, | ||||
|         "runtime": { | ||||
|           "lib/net6.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": { | ||||
|             "assemblyVersion": "6.35.0.0", | ||||
|             "fileVersion": "6.35.0.41201" | ||||
|           "lib/net9.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": { | ||||
|             "assemblyVersion": "8.0.1.0", | ||||
|             "fileVersion": "8.0.1.50722" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.IdentityModel.Tokens/6.35.0": { | ||||
|       "Microsoft.IdentityModel.Tokens/8.0.1": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.CSharp": "4.5.0", | ||||
|           "Microsoft.IdentityModel.Logging": "6.35.0", | ||||
|           "System.Security.Cryptography.Cng": "5.0.0" | ||||
|           "Microsoft.IdentityModel.Logging": "8.0.1" | ||||
|         }, | ||||
|         "runtime": { | ||||
|           "lib/net6.0/Microsoft.IdentityModel.Tokens.dll": { | ||||
|             "assemblyVersion": "6.35.0.0", | ||||
|             "fileVersion": "6.35.0.41201" | ||||
|           "lib/net9.0/Microsoft.IdentityModel.Tokens.dll": { | ||||
|             "assemblyVersion": "8.0.1.0", | ||||
|             "fileVersion": "8.0.1.50722" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Microsoft.NETCore.Platforms/1.1.0": {}, | ||||
|       "Microsoft.NETCore.Targets/1.1.0": {}, | ||||
|       "Microsoft.OpenApi/1.6.23": { | ||||
|         "runtime": { | ||||
|           "lib/netstandard2.0/Microsoft.OpenApi.dll": { | ||||
| @@ -1134,15 +1137,15 @@ | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "System.IdentityModel.Tokens.Jwt/6.35.0": { | ||||
|       "System.IdentityModel.Tokens.Jwt/8.0.1": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.IdentityModel.JsonWebTokens": "6.35.0", | ||||
|           "Microsoft.IdentityModel.Tokens": "6.35.0" | ||||
|           "Microsoft.IdentityModel.JsonWebTokens": "8.0.1", | ||||
|           "Microsoft.IdentityModel.Tokens": "8.0.1" | ||||
|         }, | ||||
|         "runtime": { | ||||
|           "lib/net6.0/System.IdentityModel.Tokens.Jwt.dll": { | ||||
|             "assemblyVersion": "6.35.0.0", | ||||
|             "fileVersion": "6.35.0.41201" | ||||
|           "lib/net9.0/System.IdentityModel.Tokens.Jwt.dll": { | ||||
|             "assemblyVersion": "8.0.1.0", | ||||
|             "fileVersion": "8.0.1.50722" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
| @@ -1166,12 +1169,6 @@ | ||||
|           "System.Collections.Immutable": "7.0.0" | ||||
|         } | ||||
|       }, | ||||
|       "System.Runtime/4.3.0": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.NETCore.Platforms": "1.1.0", | ||||
|           "Microsoft.NETCore.Targets": "1.1.0" | ||||
|         } | ||||
|       }, | ||||
|       "System.Runtime.Caching/6.0.0": { | ||||
|         "dependencies": { | ||||
|           "System.Configuration.ConfigurationManager": "6.0.1" | ||||
| @@ -1227,13 +1224,6 @@ | ||||
|         } | ||||
|       }, | ||||
|       "System.Security.Principal.Windows/5.0.0": {}, | ||||
|       "System.Text.Encoding/4.3.0": { | ||||
|         "dependencies": { | ||||
|           "Microsoft.NETCore.Platforms": "1.1.0", | ||||
|           "Microsoft.NETCore.Targets": "1.1.0", | ||||
|           "System.Runtime": "4.3.0" | ||||
|         } | ||||
|       }, | ||||
|       "System.Text.Encoding.CodePages/6.0.0": { | ||||
|         "dependencies": { | ||||
|           "System.Runtime.CompilerServices.Unsafe": "6.0.0" | ||||
| @@ -1291,6 +1281,7 @@ | ||||
|       }, | ||||
|       "Elecciones.Database/1.0.0": { | ||||
|         "dependencies": { | ||||
|           "Elecciones.Core": "1.0.0", | ||||
|           "Microsoft.EntityFrameworkCore.SqlServer": "9.0.8" | ||||
|         }, | ||||
|         "runtime": { | ||||
| @@ -1343,6 +1334,13 @@ | ||||
|       "path": "humanizer.core/2.14.1", | ||||
|       "hashPath": "humanizer.core.2.14.1.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.AspNetCore.Authentication.JwtBearer/9.0.8": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-pEuE/xaXHk2Rr2YiTraS7i2MNoTXSnX79VlJcdKx9MczrhDfBO4tHdF4HWOo542WPbjSeZx2PFjmHygo0XnK3Q==", | ||||
|       "path": "microsoft.aspnetcore.authentication.jwtbearer/9.0.8", | ||||
|       "hashPath": "microsoft.aspnetcore.authentication.jwtbearer.9.0.8.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.AspNetCore.OpenApi/9.0.5": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
| @@ -1413,13 +1411,6 @@ | ||||
|       "path": "microsoft.codeanalysis.workspaces.msbuild/4.8.0", | ||||
|       "hashPath": "microsoft.codeanalysis.workspaces.msbuild.4.8.0.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.CSharp/4.5.0": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-kaj6Wb4qoMuH3HySFJhxwQfe8R/sJsNJnANrvv8WdFPMoNbKY5htfNscv+LHCu5ipz+49m2e+WQXpLXr9XYemQ==", | ||||
|       "path": "microsoft.csharp/4.5.0", | ||||
|       "hashPath": "microsoft.csharp.4.5.0.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.Data.SqlClient/5.1.6": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
| @@ -1630,61 +1621,47 @@ | ||||
|       "path": "microsoft.identity.client.extensions.msal/4.61.3", | ||||
|       "hashPath": "microsoft.identity.client.extensions.msal.4.61.3.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.IdentityModel.Abstractions/6.35.0": { | ||||
|     "Microsoft.IdentityModel.Abstractions/8.0.1": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-xuR8E4Rd96M41CnUSCiOJ2DBh+z+zQSmyrYHdYhD6K4fXBcQGVnRCFQ0efROUYpP+p0zC1BLKr0JRpVuujTZSg==", | ||||
|       "path": "microsoft.identitymodel.abstractions/6.35.0", | ||||
|       "hashPath": "microsoft.identitymodel.abstractions.6.35.0.nupkg.sha512" | ||||
|       "sha512": "sha512-OtlIWcyX01olfdevPKZdIPfBEvbcioDyBiE/Z2lHsopsMD7twcKtlN9kMevHmI5IIPhFpfwCIiR6qHQz1WHUIw==", | ||||
|       "path": "microsoft.identitymodel.abstractions/8.0.1", | ||||
|       "hashPath": "microsoft.identitymodel.abstractions.8.0.1.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.IdentityModel.JsonWebTokens/6.35.0": { | ||||
|     "Microsoft.IdentityModel.JsonWebTokens/8.0.1": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-9wxai3hKgZUb4/NjdRKfQd0QJvtXKDlvmGMYACbEC8DFaicMFCFhQFZq9ZET1kJLwZahf2lfY5Gtcpsx8zYzbg==", | ||||
|       "path": "microsoft.identitymodel.jsonwebtokens/6.35.0", | ||||
|       "hashPath": "microsoft.identitymodel.jsonwebtokens.6.35.0.nupkg.sha512" | ||||
|       "sha512": "sha512-s6++gF9x0rQApQzOBbSyp4jUaAlwm+DroKfL8gdOHxs83k8SJfUXhuc46rDB3rNXBQ1MVRxqKUrqFhO/M0E97g==", | ||||
|       "path": "microsoft.identitymodel.jsonwebtokens/8.0.1", | ||||
|       "hashPath": "microsoft.identitymodel.jsonwebtokens.8.0.1.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.IdentityModel.Logging/6.35.0": { | ||||
|     "Microsoft.IdentityModel.Logging/8.0.1": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-jePrSfGAmqT81JDCNSY+fxVWoGuJKt9e6eJ+vT7+quVS55nWl//jGjUQn4eFtVKt4rt5dXaleZdHRB9J9AJZ7Q==", | ||||
|       "path": "microsoft.identitymodel.logging/6.35.0", | ||||
|       "hashPath": "microsoft.identitymodel.logging.6.35.0.nupkg.sha512" | ||||
|       "sha512": "sha512-UCPF2exZqBXe7v/6sGNiM6zCQOUXXQ9+v5VTb9gPB8ZSUPnX53BxlN78v2jsbIvK9Dq4GovQxo23x8JgWvm/Qg==", | ||||
|       "path": "microsoft.identitymodel.logging/8.0.1", | ||||
|       "hashPath": "microsoft.identitymodel.logging.8.0.1.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.IdentityModel.Protocols/6.35.0": { | ||||
|     "Microsoft.IdentityModel.Protocols/8.0.1": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-BPQhlDzdFvv1PzaUxNSk+VEPwezlDEVADIKmyxubw7IiELK18uJ06RQ9QKKkds30XI+gDu9n8j24XQ8w7fjWcg==", | ||||
|       "path": "microsoft.identitymodel.protocols/6.35.0", | ||||
|       "hashPath": "microsoft.identitymodel.protocols.6.35.0.nupkg.sha512" | ||||
|       "sha512": "sha512-uA2vpKqU3I2mBBEaeJAWPTjT9v1TZrGWKdgK6G5qJd03CLx83kdiqO9cmiK8/n1erkHzFBwU/RphP83aAe3i3g==", | ||||
|       "path": "microsoft.identitymodel.protocols/8.0.1", | ||||
|       "hashPath": "microsoft.identitymodel.protocols.8.0.1.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.IdentityModel.Protocols.OpenIdConnect/6.35.0": { | ||||
|     "Microsoft.IdentityModel.Protocols.OpenIdConnect/8.0.1": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-LMtVqnECCCdSmyFoCOxIE5tXQqkOLrvGrL7OxHg41DIm1bpWtaCdGyVcTAfOQpJXvzND9zUKIN/lhngPkYR8vg==", | ||||
|       "path": "microsoft.identitymodel.protocols.openidconnect/6.35.0", | ||||
|       "hashPath": "microsoft.identitymodel.protocols.openidconnect.6.35.0.nupkg.sha512" | ||||
|       "sha512": "sha512-AQDbfpL+yzuuGhO/mQhKNsp44pm5Jv8/BI4KiFXR7beVGZoSH35zMV3PrmcfvSTsyI6qrcR898NzUauD6SRigg==", | ||||
|       "path": "microsoft.identitymodel.protocols.openidconnect/8.0.1", | ||||
|       "hashPath": "microsoft.identitymodel.protocols.openidconnect.8.0.1.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.IdentityModel.Tokens/6.35.0": { | ||||
|     "Microsoft.IdentityModel.Tokens/8.0.1": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-RN7lvp7s3Boucg1NaNAbqDbxtlLj5Qeb+4uSS1TeK5FSBVM40P4DKaTKChT43sHyKfh7V0zkrMph6DdHvyA4bg==", | ||||
|       "path": "microsoft.identitymodel.tokens/6.35.0", | ||||
|       "hashPath": "microsoft.identitymodel.tokens.6.35.0.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.NETCore.Platforms/1.1.0": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", | ||||
|       "path": "microsoft.netcore.platforms/1.1.0", | ||||
|       "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.NETCore.Targets/1.1.0": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==", | ||||
|       "path": "microsoft.netcore.targets/1.1.0", | ||||
|       "hashPath": "microsoft.netcore.targets.1.1.0.nupkg.sha512" | ||||
|       "sha512": "sha512-kDimB6Dkd3nkW2oZPDkMkVHfQt3IDqO5gL0oa8WVy3OP4uE8Ij+8TXnqg9TOd9ufjsY3IDiGz7pCUbnfL18tjg==", | ||||
|       "path": "microsoft.identitymodel.tokens/8.0.1", | ||||
|       "hashPath": "microsoft.identitymodel.tokens.8.0.1.nupkg.sha512" | ||||
|     }, | ||||
|     "Microsoft.OpenApi/1.6.23": { | ||||
|       "type": "package", | ||||
| @@ -1896,12 +1873,12 @@ | ||||
|       "path": "system.formats.asn1/9.0.8", | ||||
|       "hashPath": "system.formats.asn1.9.0.8.nupkg.sha512" | ||||
|     }, | ||||
|     "System.IdentityModel.Tokens.Jwt/6.35.0": { | ||||
|     "System.IdentityModel.Tokens.Jwt/8.0.1": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-yxGIQd3BFK7F6S62/7RdZk3C/mfwyVxvh6ngd1VYMBmbJ1YZZA9+Ku6suylVtso0FjI0wbElpJ0d27CdsyLpBQ==", | ||||
|       "path": "system.identitymodel.tokens.jwt/6.35.0", | ||||
|       "hashPath": "system.identitymodel.tokens.jwt.6.35.0.nupkg.sha512" | ||||
|       "sha512": "sha512-GJw3bYkWpOgvN3tJo5X4lYUeIFA2HD293FPUhKmp7qxS+g5ywAb34Dnd3cDAFLkcMohy5XTpoaZ4uAHuw0uSPQ==", | ||||
|       "path": "system.identitymodel.tokens.jwt/8.0.1", | ||||
|       "hashPath": "system.identitymodel.tokens.jwt.8.0.1.nupkg.sha512" | ||||
|     }, | ||||
|     "System.IO.Pipelines/7.0.0": { | ||||
|       "type": "package", | ||||
| @@ -1938,13 +1915,6 @@ | ||||
|       "path": "system.reflection.metadata/7.0.0", | ||||
|       "hashPath": "system.reflection.metadata.7.0.0.nupkg.sha512" | ||||
|     }, | ||||
|     "System.Runtime/4.3.0": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", | ||||
|       "path": "system.runtime/4.3.0", | ||||
|       "hashPath": "system.runtime.4.3.0.nupkg.sha512" | ||||
|     }, | ||||
|     "System.Runtime.Caching/6.0.0": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
| @@ -1994,13 +1964,6 @@ | ||||
|       "path": "system.security.principal.windows/5.0.0", | ||||
|       "hashPath": "system.security.principal.windows.5.0.0.nupkg.sha512" | ||||
|     }, | ||||
|     "System.Text.Encoding/4.3.0": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|       "sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", | ||||
|       "path": "system.text.encoding/4.3.0", | ||||
|       "hashPath": "system.text.encoding.4.3.0.nupkg.sha512" | ||||
|     }, | ||||
|     "System.Text.Encoding.CodePages/6.0.0": { | ||||
|       "type": "package", | ||||
|       "serviceable": true, | ||||
|   | ||||
| @@ -8,7 +8,6 @@ | ||||
|       "Microsoft.AspNetCore": "Warning" | ||||
|     } | ||||
|   }, | ||||
|   "AllowedOrigins": "http://localhost:5173", | ||||
|  | ||||
|   "ComposicionCongreso": { | ||||
|     "Diputados": { | ||||
| @@ -34,5 +33,11 @@ | ||||
|         { "Id": "507_S", "Nombre": "CANDIDATURA 507", "BancasTotales": 5, "BancasEnJuego": 2, "Color": "#9467bd" } | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
|   "ApiKey": "badb1a38d221c9e23bcf70958840ca7f5a5dc54f2047dadf7ce45b578b5bc3e2", | ||||
|   "Jwt": { | ||||
|     "Key": "badb1a38d221c9e23bcf70958840ca7f5a5dc54f2047dadf7ce45b578b5bc3e2", | ||||
|     "Issuer": "EleccionesApi", | ||||
|     "Audience": "AdminPanel" | ||||
|   } | ||||
| } | ||||
| @@ -14,7 +14,7 @@ using System.Reflection; | ||||
| [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")] | ||||
| [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | ||||
| [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | ||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0d33db9e6dc7807fbb1853c621b81002ea764411")] | ||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+55954e18a797dce22f76f00b645832f361d97362")] | ||||
| [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")] | ||||
| [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")] | ||||
| [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | ||||
|   | ||||
| @@ -9,6 +9,7 @@ E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Elecciones | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Azure.Core.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Azure.Identity.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Humanizer.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.AspNetCore.Authentication.JwtBearer.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.AspNetCore.OpenApi.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Bcl.AsyncInterfaces.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Build.Locator.dll | ||||
| @@ -26,13 +27,19 @@ E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft. | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.EntityFrameworkCore.SqlServer.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Caching.Abstractions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Caching.Memory.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Configuration.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Configuration.Abstractions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Configuration.Binder.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.DependencyInjection.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.DependencyModel.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Diagnostics.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Diagnostics.Abstractions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Http.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Logging.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Logging.Abstractions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Options.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Primitives.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Identity.Client.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Identity.Client.Extensions.Msal.dll | ||||
| @@ -46,6 +53,15 @@ E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft. | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.SqlServer.Server.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Win32.SystemEvents.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Mono.TextTemplating.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.AspNetCore.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Extensions.Hosting.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Extensions.Logging.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Formatting.Compact.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Settings.Configuration.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Sinks.Console.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Sinks.Debug.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Sinks.File.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Swashbuckle.AspNetCore.Swagger.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Swashbuckle.AspNetCore.SwaggerGen.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Swashbuckle.AspNetCore.SwaggerUI.dll | ||||
| @@ -65,6 +81,7 @@ E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\System.Run | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\System.Security.Cryptography.ProtectedData.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\System.Security.Permissions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\System.Text.Json.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\System.Threading.RateLimiting.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\System.Windows.Extensions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\cs\Microsoft.CodeAnalysis.resources.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\de\Microsoft.CodeAnalysis.resources.dll | ||||
| @@ -167,19 +184,3 @@ E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\obj\Debug\net9.0\refint\Ele | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\obj\Debug\net9.0\Elecciones.Api.pdb | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\obj\Debug\net9.0\Elecciones.Api.genruntimeconfig.cache | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\obj\Debug\net9.0\ref\Elecciones.Api.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Configuration.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Configuration.Binder.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Diagnostics.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Diagnostics.Abstractions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Http.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.AspNetCore.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Extensions.Hosting.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Extensions.Logging.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Formatting.Compact.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Settings.Configuration.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Sinks.Console.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Sinks.Debug.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\Serilog.Sinks.File.dll | ||||
| E:\Elecciones-2025\Elecciones-Web\src\Elecciones.Api\bin\Debug\net9.0\System.Threading.RateLimiting.dll | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| {"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["FcPFHNuKs9rpM6p2fQ3PQFvYqx5ErYLwhh645T9bWO0=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","ZJX2c4LV\u002BYIn48VQilINT/Er9ydx\u002BF/pffY0J1mGFn4=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","HlaBteUK6BYZn6ZcnalIbUis9O08fQFj0pX7AkkgymQ="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
| {"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","GeIeP3tog3JZwKJCFe6prPm1MG/MSEFptilJTMpLZdk=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","DfeTw\u002BIdhmMK9IhKuwlSfgckGaIOiGMaYzhCKVkysII="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
| @@ -1 +1 @@ | ||||
| {"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["FcPFHNuKs9rpM6p2fQ3PQFvYqx5ErYLwhh645T9bWO0=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","ZJX2c4LV\u002BYIn48VQilINT/Er9ydx\u002BF/pffY0J1mGFn4=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","HlaBteUK6BYZn6ZcnalIbUis9O08fQFj0pX7AkkgymQ="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
| {"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","GeIeP3tog3JZwKJCFe6prPm1MG/MSEFptilJTMpLZdk=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","DfeTw\u002BIdhmMK9IhKuwlSfgckGaIOiGMaYzhCKVkysII="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
| @@ -1 +1 @@ | ||||
| {"GlobalPropertiesHash":"O7YawHw32G/Fh2bs+snZgm9O7okI0WYgTQmXM931znY=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["FcPFHNuKs9rpM6p2fQ3PQFvYqx5ErYLwhh645T9bWO0=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
| {"GlobalPropertiesHash":"O7YawHw32G/Fh2bs+snZgm9O7okI0WYgTQmXM931znY=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
| @@ -57,6 +57,10 @@ | ||||
|         "net9.0": { | ||||
|           "targetAlias": "net9.0", | ||||
|           "dependencies": { | ||||
|             "Microsoft.AspNetCore.Authentication.JwtBearer": { | ||||
|               "target": "Package", | ||||
|               "version": "[9.0.8, )" | ||||
|             }, | ||||
|             "Microsoft.AspNetCore.OpenApi": { | ||||
|               "target": "Package", | ||||
|               "version": "[9.0.5, )" | ||||
| @@ -199,7 +203,11 @@ | ||||
|         "frameworks": { | ||||
|           "net9.0": { | ||||
|             "targetAlias": "net9.0", | ||||
|             "projectReferences": {} | ||||
|             "projectReferences": { | ||||
|               "E:\\Elecciones-2025\\Elecciones-Web\\src\\Elecciones.Core\\Elecciones.Core.csproj": { | ||||
|                 "projectPath": "E:\\Elecciones-2025\\Elecciones-Web\\src\\Elecciones.Core\\Elecciones.Core.csproj" | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         }, | ||||
|         "warningProperties": { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user